2014-08-29 2 views
-2

Самообучающийся C полон сюрпризов. Я делаю это короткий фрагмент кода, чтобы проверить strcat(), который якобы присоединяет второй параметр к первому:strcat() дублирует свой второй параметр

#include <stdio.h> 
#include <string.h> 

char s1[4] = "Foo "; 
char s2[] = "Bar"; 

int main(void) { 

    strcat(s1, s2); 

    printf("%s %d %d \n", s1, strlen(s1), strlen(s2)); 
    return 0; 
} 

Я ожидал, что некоторые ошибки переполнения поскольку s1 представляет собой массив из 4-х символов, но вместо этого я получил это:

Foo BarBar BarBar 10 6 

Я сделал это в Windows, используя MS Visual Studio Express 2013 (который, кстати, поднимает некоторые предупреждения об использовании strcat). Итак ... почему strcat дублирует значение s2? Это не в документации.

+1

Чистая удача ...... – Igor

+2

Переполнение может вызывать много разных поведений. Язык не определяет, что происходит после переполнения. Это неопределенное поведение. Все может случиться! – jweyrich

+0

вам нужно понять, что C имеет модель как можно более простую. вы должны сначала адаптировать мир без исключений. – HuStmpHrrr

ответ

2

Этот

char s1[4] = "Foo "; 

создает последовательность символов s1 без нулевого терминатора. Это означает, что s1 не является строкой, и это незаконно передать его strcat. Поведение не определено.

(В приведенной выше декларации с инициализацией вы используете неясную особенность языка C, которая позволяет терминатору нуля «упасть» в конец инициализированного массива символов. В C++ эта инициализация будет плохо сформирована, так как строка инициализации требует буфер размером 5, а не 4.)

на практике это приводит strcat пробегать к концу s1 массива и в s2 (по-видимому, случайно расположенный рядом в памяти) ищет нулевой терминатор в первый аргумент. Таким образом, в конце вы добавляете s2 в комбинацию из s1+s2 в память, что создает эффект дублирования s2. Излишне говорить, что результат не имеет смысла.

Конечно, даже с s1 размера 5 код по-прежнему демонстрирует неопределенное поведение, поскольку в целевом буфере нет места для результата конкатенации. Размер s1 должен быть не менее 8, чтобы результат попал в него.

0

первый: s1 не оканчивается нулем

второй: вы выделения статической памяти для s1 и s2. компилятор обычно упаковывает их в общий блок данных вашего исполняемого файла. если вы читаете границу s1, которую вы читаете в этот блок, так как ваша программа «владеет» этой памятью, ОС не будет жаловаться на нее.

0

Первое, что нужно отметить, это то, что строка C «завершена нулем», то есть она заканчивается нулевым байтом («\ 0») (и, следовательно, не может содержать несколько нулевых байтов). Итак, строка «Foo» на самом деле пять символов длиной {'F', 'o', 'o', ' ', '\0'}.

Вы определяете массив из 4 символов и заполняете его пятью элементами. char s1[4] = "Foo "; Это означает, что следующий массив, s2, который, вероятно, будет помещен рядом с первым, перезапишет нулевой байт s1.

Поскольку строки C определены до нулевого байта, strcat будет копировать символы из первой строки до тех пор, пока не достигнет нулевого байта. Но, поскольку s2 перезаписал нулевой байт, первым пустым знаком strcat является значение null от s2. С точки зрения strcat, s1 выглядит как "Foo Bar\0";

+0

" определяют массив из 4 символов и заполняют его пятью элементами. char s1 [4] = "Foo"; ... "неверен. Только первые 4 элемента помещаются в 's1'. – chux

+0

Правда; «пятый» элемент фактически является частью 's1'. –

+0

Чтобы быть ясным, 5-й элемент '' Foo'' не помещается нигде. Ни в 's1', ни' s2'. – chux

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