SIGSEV в строке строки memset - PullRequest
0 голосов
/ 28 июня 2019

В следующей программе я ожидаю остановки цикла for после 3 элементов.Но он продолжает работать бесконечно и в дальнейшем завершается неудачей с coredump.

  1. is malloc() needed for char * [] `
  2. приведет к сбою strcmp, если я установлю значение 0?

.

#include<stdio.h>
#include<string.h>
#include<stdlib.h>
int main()
{
        char* str[10]; memset(str,0,10);

        str[0]=malloc(sizeof(char)*(strlen("Sample")+1));
        str[1]=malloc(sizeof(char)*(strlen("Sample")+1));
        str[2]=malloc(sizeof(char)*(strlen("Sample")+1));

        strcpy(str[0],"Sample");
        strcpy(str[1],"Sample");
        strcpy(str[2],"Sample");



        int i=0;
        for(i=0;strcmp("",str[i])!=0;i++)
        {
                printf("%d\n",i);;
        }
        return 0;
}

Редактировать: Даже с char* str[10]; memset(str,0,10*sizeof(char*)); код все еще дает дамп ядра

Ответы [ 3 ]

3 голосов
/ 28 июня 2019

Подводя итог всему изложенному в комментариях и других ответах, здесь есть как минимум три (или, если хотите быть педантичными, четыре) проблемы:

  1. Вам нужно memset(str, 0, 10*sizeof(char *) (но смотрите #4 ниже).
  2. Вам необходимо проверить нулевые указатели перед вызовом strcmp, используя условие типа str[i] != NULL && strcmp("",str[i])!=0 в цикле for.
  3. Если вы когда-либо сохраните 10 непустых строкв массиве цикл будет уходить с конца, никогда не находя пустую строку.
  4. (педантичный) memset не является хорошим способом инициализации массива нулевых указателей.(Строго говоря, это совсем не гарантируется.) Как подсказывает @ user3121023 в комментарии, лучше использовать char *str[10] = { NULL }.

Вместо использования пустой строки (или нулевого указателя)в качестве маркера конца вашего массива строк вы можете рассмотреть возможность сохранения явного счетчика в отдельной переменной.Это, вероятно, более распространенный подход.


Приложение.Вы спрашивали, нужно ли вам выделять строки.Память для строк должна быть выделена, но вам не обязательно динамически выделять ее, вызывая malloc.Существует как минимум три способа добиться необходимого выделения, и в двух из них компилятор сделает это за вас.Вот пример всех трех:

char sample1[] = "Sample 1";

char *sample2 = malloc(strlen("Sample 2") + 1);
strcpy(sample2, "Sample 2");

str[0] = "Sample 0";
str[1] = sample1;
str[2] = sample2;
2 голосов
/ 28 июня 2019
  1. - это malloc (), необходимый для char * [] `

В C ++ вряд ли когда-либо понадобится malloc.

В C обычно требуется malloc, но только если вам нужно динамически распределять.

В общем случае наличие символа * [] не означает, что вам обязательно нужно динамическое размещение и, следовательно, нет необходимости в malloc.

если я не использую malloc для каждого элемента массива str [], то было бы неправильно назначать строку без выделения памяти для этой строки?

Символ * не должен указывать на память, выделенную с помощью malloc. Например, он может указывать непосредственно на строковый литерал (только в C; в C ++ вам нужен указатель на const). Или это может указывать на память в стеке.

не символ * ул; strcpy (str, "sample") неправильно, если я не выделяю память для str через malloc?

Это неправильно, но не потому, что вы не используете malloc. Это неправильно, потому что вы передаете неинициализированный указатель в strcpy. Поэтому поведение не определено. Это не имеет ничего общего с malloc.


  1. не сможет strcmp ...

Непонятно, что вы подразумеваете под "неудачей". Нет выходных данных, которые означают сбой или ошибку. Для некоторых входных данных поведение не определено. В то время как неопределенное поведение является ошибкой программиста, нет гарантии поведения, которое вы могли бы считать ошибочным.

... если я установил значение 0?

Если вы передадите указатель на strcmp, который не является указателем на строку с нулевым символом в конце, то поведение программы не определено.

В программе, которую вы показываете, вы заканчиваете тем, что передаете неинициализированный указатель или тот, у которого memset был установлен в 0, и поэтому нет гарантии, что они будут указателем на завершенную нулем строку. Поэтому поведение программы не определено.

Я передаю указатель, указывающий на 0 (ноль), поэтому разыменование не должно сталкиваться с проблемой отсутствия строки с нулевым символом в конце, так как мы ничего не храним в нулевом местоположении

Memset в 0 не гарантируется равным нулю, что касается стандарта. Даже если в вашей системе, вероятно, указано значение null, 10 байтов, вероятно, недостаточно для 4 указателей в этой системе, как указывает @ChristianGibbons, так что вы фактически не инициализировали все указатели вообще.

Даже если вы инициализировали указатели на null, нулевой указатель не является указателем на строку с нулевым окончанием, и, следовательно, передача нулевого указателя в strcmp имеет неопределенное поведение.

2 голосов
/ 28 июня 2019
for(i=0;strcmp("",str[i])!=0;i++)

Вы разыменовываете размеченный указатель

for(i=0;str[i];i++)

Но он не будет работать, так как

memset(str,0,10);

Не инициализирует весь массив

memset(str,0,10*sizeof(char *);
...