2012-03-15 2 views
1

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

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!

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

+1

Что не работает? Что на самом деле происходит и что вы ожидали? –

ответ

2

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

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; 
} 

EDIT

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

2

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

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

4

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

строки = строка + я;

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

static void remove_leading_spaces(char** line) 
{ 
    int i; 
    for(i = 0; (*line)[i] == ' '; i++);  
    *line = *line + i; 
} 
1

Попробуйте

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

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

+0

Аргументы 'strcpy'' 'ограничены '', что означает (среди прочего), что строки, которые не могут накладываться, не могут пересекаться, иначе это приведет к неопределенному поведению. Вместо этого следует использовать 'memmove'. – jwodder

+0

Ваше право - должно действительно ложиться спать !. Редактировал. –

1

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

2

Код пропускает только пробелы, а не общее пробелы (в том числе вкладки, новые строки и т. Д.). Таким образом, более общее решение будет использовать 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 типа, как и на некоторых системах.

1

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

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

+0

Postfix '++' имеет более высокий приоритет, чем унарный '*', поэтому '* cpp ++' анализирует как '* (cpp ++)', что не то, что вы хотите. Вместо этого используйте '(* cpp) ++'. – jwodder

Смежные вопросы