Плохой доступ к памяти при копировании строки без пробела
Это структура, которая у меня есть
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.