strcpy ведет себя иначе, если строка назначения неинициализирована - PullRequest
0 голосов
/ 27 ноября 2011

Я работаю в C, пытаясь создать декодер Хаффмана.Этот фрагмент кода работает только в том случае, если кодовый массив входит в неинициализированный, иначе он вызывает ошибку сегментации.Тем не менее, valgrind жалуется, что codearray не инициализируется, если я делаю это таким образом.Я прошел через это с ddd, и ошибка сегментации происходит, когда вызывается strcpy, и я не могу понять, почему.

void printtree_inorder(node* n,char* code,char* letarray,char** codearray)
{
    if (n == NULL) {
        return;
    }
    static int counter=0;
    appenddigit(code,'0');
    printtree_inorder(n -> left,code,letarray,codearray);
    remdigit(code);
    if (n->let!='\0') {
       letarray[counter]=n->let;
       strcpy(codearray[counter],code);
       counter++;
    }
    appenddigit(code,'1');
    printtree_inorder(n -> right,code,letarray,codearray);
    remdigit(code);
}

Вот вызывающая функция:

char code[100]={'\0'};
char** codearray=(char**)malloc(numchars*sizeof(char*));
for (i=0;i<numchars;i++) {
    codearray[i]=(char*)malloc(100*sizeof(char));
}


char* letarray=(char*)malloc((numchars+1)*sizeof(char));
letarray[0]='\0';

printtree_inorder(root,code,letarray,codearray);

Ответы [ 2 ]

1 голос
/ 27 ноября 2011
for (i=0;i<numchars;i++) {
    codearray[i]=(char*)malloc(100*sizeof(char));
}

это код, о котором вы говорите?на самом деле это не код инициализации, он освобождает место для кода данных.

char** codearray=(char**)malloc(numchars*sizeof(char*));

просто создает вам массив char *, но они не указывают на допустимую память.Итак, ваш «код инициализации» просто гарантирует, что ваша память создана правильно.

Другая вещь, которая меня действительно пугает, это то, что ваша переменная-счетчик является статической.вызов

printtree_inorder(root,code,letarray,codearray);
printtree_inorder(root,code,letarray,codearray);

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

char* code = (char *)malloc(numchars + 1);
memset(code, 0, numchars + 1);

char* letarray = (char *)malloc(numchars + 1);
memset(letarray, 0, numchars + 1);

char** codearray = (char **)malloc(numchars * sizeof(char *));
memset(codearray, 0, numchars * sizeof(char *));

printtree_inorder(root, code, letarray, codearray, 0);

free(code);
// do not forget the free the other allocations later as well as


void printtree_inorder(node* n,char* code,char* letarray,char** codearray, int counter)
{
    if (n == NULL) {
        return;
    }
    appenddigit(code,'0');
    printtree_inorder(n -> left,code,letarray,codearray, counter);
    remdigit(code);
    if (n->let!='\0') 
    {
       letarray[counter] = n->let;
       codearray[counter] = strdup(code);
       ++counter;
    }
    appenddigit(code,'1');
    printtree_inorder(n -> right,code,letarray,codearray, counter);
    remdigit(code);
}
0 голосов
/ 27 ноября 2011

Вероятно, при "инициализированном" вызове массив не совсем правильно инициализирован, поэтому функция аварийно завершает работу.

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

Функция пытается скопировать строку туда, куда codearray[counter] указывает на:

strcpy(codearray[counter],code);

В вызове функции показано, что codearray[counter] является случайным значением, поскольку только массив был выделен malloc, но элементы не были инициализированы какими-либо конкретными значениями.strcpy() затем пытается записать этот случайный адрес памяти.

Вы должны выделить память для копии строки, например, используя strdup() вместо strcpy().

...