2012-04-27 2 views
2

У меня есть программа, в которой я хотел удалить пробелы из строки. Я хотел найти изящный способ сделать так, чтобы я нашел следующее (я изменил его немного, так что может быть лучше для чтения) код in a forum:Как C знает конец моей строки?

char* line_remove_spaces (char* line) 
{ 
    char *non_spaced = line; 
    int i; 
    int j = 0; 
    for (i = 0; i <= strlen(line); i++) 
    { 
     if (line[i] != ' ') 
     { 
      non_spaced[j] = line[i]; 
      j++; 
     } 
    } 
    return non_spaced; 
} 

Как вы можете видеть, функция принимает string и, используя одно и то же выделенное пространство памяти, выбирает только нерасширенные символы. Оно работает!

В любом случае, согласно Википедии, строка в C является «Null-terminated string». Я всегда так думал, и все было хорошо. Но проблема в том, что в конце строки non_spaced мы не помещаем «нулевой символ». И каким-то образом компилятор знает, что он заканчивается последним символом, измененным строкой «non_spaced». Как это знать?

+0

Что вы подразумеваете под «компилятор знает это»? Вы меняете его во время выполнения, процесс компиляции долгое время. – Fred

+0

@Fred - хорошая точка! –

+2

Для чего это стоит, 'strlen (line)' будет пересчитывать длину строки когда-либо y время. Это нетривиальный расчет и не должен выполняться на каждой итерации цикла. Вы бы гораздо лучше вычислили его один раз и сохранили его: 'size_t len ​​= strlen (line); для (i = 0; i <= len; i ++) '. (Кроме того, все переменные, которые у вас есть как 'int', должны технически быть типом 'size_t'.) –

ответ

9

Это не происходит по волшебству. У вас есть в вашем коде:

for (i = 0; i <= strlen(line); i++) 
       ^^ 

индекс цикла i продлится до strlen(line) и в этом индексе есть нулевой символ в массив символов, и это становится скопирован. В результате ваш конечный результат имеет нулевой характер по желаемому индексу.

Если у вас

for (i = 0; i < strlen(line); i++) 
       ^^ 

, то вы должны были поставить пустой символ вручную:

for (i = 0; i < strlen(line); i++) 
{ 
    if (line[i] != ' ') 
    { 
     non_spaced[j] = line[i]; 
     j++; 
    } 
} 
// put nul character 
line[j] = 0; 
+0

. Нулевой символ будет '\ 0' не '' – KBN

+0

@xFortyFourx: http: //stackoverflow.com/questions/4705968/what-is-value-of-eof-and-0-in-c – codaddict

+0

Вау! Я бы никогда этого не понял. Благодаря! (серьезно, я не заметил «<=» там) – vaulttech

0

Вы можете попробовать. Отлаживайте его, пока он обрабатывает строку, содержащую только одно пространство: ''. Следите внимательно за тем, что происходит с индексом i.

0

Откуда вы знаете, что оно «знает»? Наиболее вероятный сценарий заключается в том, что вам просто повезло с вашим неопределенным поведением и что есть '\0' -character после действительных байтов line.

Также весьма вероятно, что вы не видите пробелы в конце, которые могут быть напечатаны, прежде чем попасть в бродячую «повезло '\0'».

Несколько моментов:

  • Там нет необходимости писать это с помощью индексации.
  • Невозможно вызвать strlen() на каждой итерации цикла.
  • Возможно, вы захотите использовать isspace(), чтобы удалить лишние символы.

Вот как я бы написать его, используя isspace() и указатели:

char * remove_spaces(char *str) 
{ 
    char *ret = str, *put = str; 

    for(; *str != '\0'; str++) 
    { 
    if(!isspace((unsigned char) *str) 
     *put++ = *str; 
    } 
    *put = '\0'; 

    return ret; 
} 

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

+1

Нет, код не определен. Он будет работать - проверьте оператор сравнения. –

+0

Если строка 'строка' - это строка с нулевым завершающим символом, то' non_spaced' гарантированно завершается нулем, поэтому это не «повезло» \ 0' » – Anthales

2

Цикл использует <= strlen, поэтому вы также скопируете нулевой ограничитель (который находится в i == strlen(line)).

0

Параметр струну функции завершается нулем, верно? И в цикле нулевой символ исходной строки также копируется в нераспределенную возвращаемую строку. Таким образом, нераспределенная строка на самом деле также заканчивается на нуль!

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

3

Другие ответили на ваш вопрос уже, но здесь это быстрее, и, возможно, понятнее версия одного и того же кода:

void line_remove_spaces (char* line) 
{ 
    char* non_spaced = line; 

    while(*line != '\0') 
    { 
    if(*line != ' ') 
    { 
     *non_spaced = *line; 
     non_spaced++; 
    } 

    line++; 
    } 

    *non_spaced = '\0'; 
} 
0

, если вы используете "< = STRLEN (линия), длина от STRLEN (строка) включают '\ 0' , поэтому ваша программа может работать. Вы можете использовать анализ отладки и запуска.

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