Функция удаления начальных пробелов не меняет строку в вызывающей программе? - PullRequest
1 голос
/ 15 марта 2012

У меня есть функция, которая должна удалить начальные пробелы из строки.По какой-то причине это не работает:

static void remove_leading_spaces(char* line)
{  
   int i;
   for(i = 0; line[i] == ' '; i++);      //iterate through till whitespace     
   line = line + i;                      //  advance the pointer to point to
                                         //  the first non space character
}

Например, если у меня есть строка с одним пробелом в начале, строка не будет изменена.

Спасибо всем за ответыисправить для remove_leading_spaces!

Как бы я сделал это со строкой, которую нужно вернуть из функции, которая вызывает эту функцию?Я пробовал тот же подход, и я продолжаю получать ошибку сегментации?Это точно такая же концепция?

Ответы [ 7 ]

4 голосов
/ 15 марта 2012

Параметры передаются по значению в C. Таким образом, даже если вы измените значение line здесь:

line = line + i;

значение указателя, который вы передаетев remove_leading_spaces() не меняется.Если вы хотите, чтобы это изменило указатель в вызывающем абоненте, вам нужно будет передать адрес указателя (как вы передаете по ссылке в C):

static void remove_leading_spaces(char** line)
{  
   int i;
   for(i = 0; (*line)[i] == ' '; i++);     
   *line = *line + i;
}
2 голосов
/ 15 марта 2012

Код пропускает только пробелы, а не общий пробел (который включает в себя вкладки, новые строки и т. Д.). Таким образом, более общее решение будет использовать isspace() из #include <ctype.h> (или вы будете использовать «пробелы» или «пробелы» вместо «пробелы»).

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

static char *find_first_non_white_space(char *line)
{
    while (isspace((unsigned char)*line))
        line++;
    return line;
}

Или с индексами:

static char *find_first_non_white_space(char *line)
{
    int i = 0;
    while (isspace((unsigned char)line[i]))
        i++;
    return &line[i];
}

Приведение необходимо, если char имеет тип signed, как в некоторых системах.

2 голосов
/ 15 марта 2012

В приведенной ниже функции вы передаете указатель по значению.

static void remove_leading_spaces(char* line) 

Это означает, что любое изменение в line в теле не отражается в вызывающей программе.Вам нужно изменить свою функцию следующим образом:

static void remove_leading_spaces(char** line) 
{   
   int i; 
   for(i = 0; (*line)[i] == ' '; i++) { } // the ';' is a HUGE TRAP prefer { }
   *line += i;
} 

РЕДАКТИРОВАТЬ

Будьте осторожны, НЕ освобождая line после этого, поскольку вы не освободите всю строку.Если память была выделена динамически, вам необходимо сохранить резервную копию исходного указателя, чтобы безопасно ее освободить.

2 голосов
/ 15 марта 2012

Поскольку вы передаете line по значению, вы изменяете его копию внутри функции, но переменная, которую вы передаете этой функции в вызывающем коде, не изменится. Один из способов исправить это - передать указатель вашей функции на строку C, то есть char **line вместо char *line.

Имейте в виду, однако, что в зависимости от того, как вы распределяете вашу строку, вы можете потерять память, просто продвигая указатель вперед, и вы определенно не сможете освободить ее позже. Лучший способ сделать это - скопировать оставшуюся часть строки в исходное начало; это будет менее «эффективным», но более правильным в долгосрочной перспективе. И вам даже не придется менять сигнатуру функции.

1 голос
/ 15 марта 2012

Когда вы изменяете указатель в методе, он не меняет указатель, который был передан на вызывающей стороне. Если вы хотите изменить это, вам нужно передать указатель на этот указатель (char **cpp) и изменить его через него ((*cpp)++).

Если строка была malloc ed, не забудьте сохранить еще один указатель, чтобы вы могли его освободить.

1 голос
/ 15 марта 2012

Функция только изменяет значение line в рамках функции. Самое простое решение для remove_leading_spaces - вернуть line + i, и вызывающий код должен присвоить это возвращаемое значение переменной в пределах своей области видимости.

1 голос
/ 15 марта 2012

Попробуйте

static void remove_leading_spaces(char* line)
{
   char *copyFrom = line;
   for (; *copyFrom && ' ' == *copyFrom; ++copyFrom);
   memmove(line, copyFrom, strlen(copyFrom));
}

Это изменит строку, чтобы быть частью после начальных пробелов. Обратите внимание, что это также работает, если есть только начальные пробелы.

...