Что не так с этой функцией? - PullRequest
4 голосов
/ 27 февраля 2010

У меня сегодня проблема. У него был метод, и мне нужно найти проблему в этой функции. Цель функции - добавить новую строку в передаваемую строку. Ниже приведен код

char* appendNewLine(char* str){
    int len = strlen(str);
    char buffer[1024];
    strcpy(buffer, str);
    buffer[len] = '\n';
    return buffer;
}

Я обнаружил проблему с этим методом. Своего рода прямо вперед. Этот метод может привести к тому, что индекс массива выйдет за пределы диапазона. Это не мое сомнение. В Java я использую '\ n' для перевода строки. (Я в основном программист на Java, я много лет работал в C). Но я смутно помню, что \ n означает обозначение завершения строки в C. Это также проблема с этой программой?

Пожалуйста, сообщите.

Ответы [ 13 ]

9 голосов
/ 27 февраля 2010

В этом коде немало проблем.

  1. strlen и not strlent, если у вас там нечетная библиотечная функция.
  2. Вы определяете статический буфер в стеке. Это потенциальная ошибка (в том числе и с точки зрения безопасности), так как через строку вы копируете строку без проверки длины. Возможными решениями этого могут быть либо выделение памяти в куче (с комбинацией strlen и malloc), либо использование strncpy и принятие отсечения строки.
  3. Добавление '\ n' действительно решает проблему добавления новой строки, но это создает еще одну ошибку в том, что строка в настоящее время не завершена нулем. Решение: добавьте '\ n' и '\ 0' к нулю, чтобы завершить новую строку.
  4. Как уже упоминали другие, вы возвращаете указатель на локальную переменную, это серьезная ошибка и делает возвращаемое значение поврежденным в течение короткого времени.

Чтобы расширить ваше понимание этих проблем, пожалуйста, посмотрите, что такое строки в стиле C, потенциально из здесь . Кроме того, изучите разницу между переменными, расположенными в стеке, и переменными, расположенными в куче.

РЕДАКТИРОВАТЬ: AndreyT является правильным, определение длины является действительным

7 голосов
/ 27 февраля 2010

Нет, '\ n' - это новая строка в c, как и в Java (Java взяла это из C). Вы определили одну проблему: если длина строки ввода превышает buffer, вы будете писать после конца buffer. Хуже того, ваш return buffer; возвращает адрес памяти, который является локальным для функции и прекратит свое существование при выходе из функции.

5 голосов
/ 27 февраля 2010

Во-первых, это функция, а не программа.

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

Другая проблема, если переданный длиннее 1024 символов; в этом случае strcpy() запишет за буфер. Одним из решений является выделение нового буфера в динамической памяти и возврат указателя на этот буфер. Размер буфера должен быть len +2 (все символы + newline + \0 терминатор строки), но кто-то должен будет освободить этот буфер (и, возможно, также исходный буфер).

strlent() не существует, должно быть strlen(), но я полагаю, что это просто опечатка.

3 голосов
/ 27 февраля 2010

C-строки заканчиваются на «\ 0».
А так как ваша цель - добавить newLine, следующее будет хорошо (сэкономит вам копирование всей строки в буфер):

char* appendNewLine(char* str){
    while(*str != '\0') str++;  //assumming the string ended with '\0'
    *str++ = '\n';  //assign and increment the pointer
    *str = '\0';
    return str;  //optional, you could also send 0 or 1, whether 
                 //it was successful or not
}

РЕДАКТИРОВАТЬ:
Строка должна иметь место для размещения дополнительных символов \ n, и поскольку OBJECTIVE должен сам добавляться, что означает добавление к оригиналу, можно предположить, что в строке есть место как минимум еще для одного символа !!
Но, если вы не хотите что-либо предполагать,

char* appendNewLine(char* str){
    int length = strlen(str);
    char *newStr = (char *)malloc(1 + length);
    *(newStr + length) = '\n';
    *(newStr + length + 1) = '\0';
    return newStr;
}
3 голосов
/ 27 февраля 2010

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

Вам необходимо выделить память, используя malloc или аналогичный, если вы собираетесь вернуть ее из функции.

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

2 голосов
/ 27 февраля 2010

В вашей программе есть как минимум две проблемы.

Во-первых, вы, кажется, хотите построить строку, но никогда не завершаете ее нулем.

Во-вторых, ваша функция возвращает указатель на локально объявленный буфер. Делать это не имеет смысла.

2 голосов
/ 27 февраля 2010

Терминатором для строки в C является '\ 0', а не '\ n'. Это означает только перевод строки.

2 голосов
/ 27 февраля 2010

Добавить ноль после новой строки:

buffer[len] = '\n';
buffer[len + 1] = 0;
1 голос
/ 28 мая 2014

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

int len = strlen(str);
char buffer[1024];
...
buffer[len] = '\n';

Если strlen (str)> 1024, то эта последовательность будет записывать за пределы объявленного буфера. Также, как отмечено, это (вероятно) не будет нулевым завершением.

Чтобы безопасно добавить новую строку, если это возможно,

char buffer[1024];
strncpy(buffer, str, 1024); // truncate string if it is too long
int len = strlen(buffer);
if (len < 1022) {
   buffer[len] = '\n';
   buffer[len + 1] = '\0';
} 

Примечание. Если строка слишком длинная, это оставляет усеченную строку БЕЗ новой строки.

1 голос
/ 27 февраля 2010
char* appendNewLine(char* str){
    int len = strlen(str);
    char buffer[1024];
    strcpy(buffer, str);
    buffer[len] = '\n';
    return buffer;
}

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

Используйте вместо malloc

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...