2016-11-03 3 views
-1

Так что я изучаю C медленно, но верно, и я смущен этими выходами.Char array manipulatiion

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


int main() { 

     mycat(5); 
     mycat(7); 
     mycat(30); 

     return 0; // from everything I've read this is necessary...? 

} 

char dest_buffer[100]; 
char str1[] = "Hello"; 
char str2[] = "World"; 

void mycat(int n) { 

    strcat(str1, str2); 
    memcpy(dest_buffer, str1, n); 
    printf("%s\n", dest_buffer); 

} 

Это выходные данные, которые я получаю.

>Hello 
>HelloWo 
>HelloWorldorldorldorld 

Последний, в соответствии с указаниями, должен просто вернуть HelloWorld. Я не совсем уверен, почему он просто продолжает говорить «orld» раз после него. Любая помощь, помогающая в исправлении этого, была бы замечательной! Я не слишком уверен, что делать здесь.

+4

Вы получаете доступ к нераспределенной памяти, поэтому это UB, и это будет отличаться от компилятора к компилятору. –

+0

Например, с 'gcc' и' clang', я получаю прерывание вызова. Однако не все компиляторы сделают это. –

+0

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

ответ

0

Две вещи могут помочь понять, почему программа ведет себя таким образом. Во-первых, понять, что строки символов в C обычно завершаются нулевым байтом, поэтому для начала «Hello» на самом деле составляет 6 байтов. Во-вторых, статически назначенные переменные хранятся в стеке в непрерывной памяти, поэтому вы можете думать о str1 и str2 как о взятии 12 последовательных байтов.

В вашей функции вы вызываете strcat, который копирует байты из str2 на str1, начиная с нулевого байта. После первого вызова эти 12 байтов выглядят как «HelloWorld \ 0 \ 0», потому что вы скопировали нулевой байт в первой строке, а strcat null завершили вывод. Str2 все еще указывает на 7-й байт тех 12, которые «orld \ 0 \ 0». Следующий вызов strcat добавит «orld» к строке, предоставив вам «HelloWorldorld \ 0». В этот момент str2 указывает на «orldorld \ 0», а третий вызов strcat добавит эти байты.

Итак, когда вы вызываете memcpy для копирования n байтов, вы получаете строку, на которую указывает str1. Важный момент здесь: вы статически выделили 6 байтов на str2, и ваш код вышел из выделенного пространства в память, вероятно, используется чем-то еще в стеке. Это очень плохо, и он связан с segfault.

1

Чтобы получить лучшее представление о том, что происходит, измените длину своих массивов str1 и str2 на длину 100, чтобы мы не получили странное, неопределенное поведение.

@Eli Sadoff абсолютно верно; когда вы определяете строку, такую ​​как char str1[] = "Hello", тогда выделенная часть памяти имеет всего 6 байтов: 5 символов плюс терминатор NULL. Когда вы объединяете строки с strcat, вы должны убедиться, что у вашего адресата достаточно памяти. Вот полезный ресурс для реализации FreeBSD о strcat, которые вы можете найти полезным: https://www.freebsd.org/cgi/man.cgi?query=strcat&apropos=0&sektion=0&manpath=FreeBSD+10.3-RELEASE+and+Ports&arch=default&format=html

Давайте печатать str1 и маркировать наши printf заявления.

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

char dest_buffer[100]; 
char str1[100] = "Hello";     // changed to 100 
char str2[100] = "World";     // changed to 100 

void mycat(int n) { 
    strcat(str1, str2); 
    printf("str1 = %s\n, str1);   // added so you can see str1 
    memcpy(dest_buffer, str1, n); 
    printf("buffer = %s\n", dest_buffer); // labeled buffer printout 
} 

int main() { 
    mycat(5); 
    mycat(7); 
    mycat(30); 
    return 0; 
} 

Выход:

str1 = HelloWorld 
buffer = Hello 
str1 = HelloWorldWorld 
buffer = HelloWo 
str1 = HelloWorldWorldWorld 
buffer = HelloWorldWorldWorld 

На ваш вопрос: почему последняя строка сказать World 3 раза? Это связано с тем, что каждый раз, когда вы звоните mycat, вы вызываете метод strcat(str1, str2), который помещает str2 и терминатор /0 в конец str1, начиная с первого /0 в str1.

Итак, вы видите, str1 получает еще одну копию str2 прилагаемую каждый раз, когда вы называете mycat, а затем вы делаете memcpy только на n байт, и всегда, начиная с начала буфера. Вот почему, когда вы печатаете buffer, он иногда усекается.