Плохой доступ к памяти при копировании строки без пробела

Это структура, которая у меня есть

typedef struct {
    int  startIndex;
    int length;
    char *rawString;
}Tokenizer;

У меня есть функция для копирования строки (которая будет вырезать пространство)

void copyStringWithoutSpace(char *source,char *destination )
{
    int i =0 ,j=0;

    destination = malloc (sizeof(char)*strlen(source));
    for(i=0;i<strlen(source);i++)
    {
        if(!(source[i]==' ')||(source[i]=='\t'))
        {
            destination[j] =source[i];
            j++;
        }
    }
    destination[j]='\0';
}

И это функция, которая вызывает copyStringWithoutSpace

Tokenizer *initTokenizer(char *expression)
{
    int i =0, j=0;
    Tokenizer *newTokenizer = malloc (sizeof(Tokenizer));
    copyStringWithoutSpace(expression, newTokenizer->rawString);
    newTokenizer ->startIndex =0;
    newTokenizer ->length =strlen(newTokenizer->rawString);
    return newTokenizer;
}

Теперь этот код вернет плохой доступ к памяти. У меня есть устранение неполадок так долго и не могу решить. Кто-нибудь хочет мне помочь?

1 ответ

Решение

Будьте осторожны, строки C заканчиваются символом NULL, и этот символ не учитывается strlenЭто означает, что его размер в памяти на самом деле strlen(source) + 1,

Что вам нужно сделать, это выделить свой буфер следующим образом:

destination = malloc (strlen(source) + 1);

sizeof(char) по стандарту C гарантированно равен 1, так что вы можете безопасно его пропустить.

Кроме того, вы изменяете значение destination переменная внутри copyStringWithoutSpace функция, которая означает, что вновь выделенная память не будет видна снаружи функции, и это приведет к утечке памяти.

Вам нужно либо вернуть указатель, и иметь следующую подпись:

char * copyStringWithoutSpace(char *source)

или альтернативно:

void copyStringWithoutSpace(char *source, char ** destination)

где вы должны будете выделить память следующим образом:

*destination = malloc (strlen(source) + 1);

Вот еще одна ошибка: if(!(source[i]==' ')||(source[i]=='\t'))

Это не делает то, что вы хотите, из-за приоритета оператора. Здесь оператор отрицания применяется только к следующей паре скобок, что означает, что ваш тест можно записать так:

если источник [i] не является пробелом, или источник [i] является табуляцией

Вы должны были написать это так:

if (source[i] != ' ' && source[i] != '\t')

Что гораздо понятнее, не так ли?

Затем также, как указано в комментарии, призывая strlen на каждой итерации очень неэффективно, потому что всю строку нужно повторять до символа NULL.

Другие вопросы по тегам