2013-06-11 2 views
2

В качестве упражнения в указателях я сделал функцию конкатенации:Строка перемещается неожиданно в C

void 
strcat(char *s, char *t) 
{ 
    while(*s) 
     s++; 
    while(*s++ = *t++); 
} 

, кажется, работает просто отлично:

main() 
{ 
    char *s = "Hello, "; 
    char *t = "world!"; 

    strcat(s,t); 
    printf("%s\n", s); 

    return 0; 
} 

производит Hello, world!, как ожидалось. Но случилось что-то нежелательное, напечатав строку t баллов, чтобы дать orld!. strcat не может быть изменен t. Вместо этого кажется, что строка перемещена; декремент t после strcat, а затем его печать дает правильную строку.

Что перенесло строку? strcat должно быть, но не знаю, в чем проблема.

Скомпилировано в версии tcc 0.9.26 (x86-64 Win64), если это имеет значение.

+0

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

ответ

4

Это неопределенное поведение:

  • Вы пишете в пространство, выделенное для строкового литерала, и
  • Вы пишете мимо выделенного пространства.

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

main() 
{ 
    char s[14] = "Hello, "; // 14 is enough to fit Hello, world!\0 
    char *t = "world!"; 

    strcat(s,t); 
    printf("%s\n", s); 

    return 0; 
} 

Примечание: Вы можете изменить подпись вашей функции, чтобы указать, что вторая строка не модифицируются:

void strcat(char *s, const char *t) 
1

Попробуйте что-нибудь еще вдоль линии:

main() 
{ 
    char *s = "Hello, "; 
    char newStr[256]; 
    strcpy(newStr, s); 

    char *t = "world!"; 

    strcat(newStr,t); 
    printf("%s\n", newStr); 

    return 0; 
} 

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

2

Ваша переменная t с ее содержимым «world! \ 0» находится в памяти сразу после вашей другой переменной s, которая содержит «Hello, \ 0». Ваша функция strcat перезаписала нулевой ограничитель в переменной s и продолжала перезаписывать память в переменную t.

Первоначально выделенная память может отображаться как «Hello, \ 0world! \ 0» После запуска вашей функции strcat ее можно было бы отобразить как «Hello, world! \ 0 \ 0» Последний нулевой ограничитель никогда изменилось, но все остальное выглядит так, как будто оно перемещено влево, потому что ваша функция strcat перезаписала первый нулевой ограничитель.

Ваш указатель t по-прежнему указывает на место памяти, в котором он находился раньше. Поскольку память там изменилась, содержимое в t можно показать как «orld! \ 0 \ 0».

Когда вы печатаете это, оно отображается как «orld!».

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

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