#c #pointers #while-loop
Вопрос:
Я начал изучать Си, и у меня было это упражнение из книги «Прентис Холл — Язык программирования Си«.
Глава 5 Упражнение 3. Напишите версию указателя функции strcat, которую мы показали в главе 2. strcat(s, t) копирует строку t в конец s.
Я выполнил упражнение, но первый метод, который пришел мне в голову, был:
void stringcat(char *s, char *t){ int i,j; i = j = 0; while(*(s i) != ''){ printf("%d", i); i ; } while ( (*(t j)) != ''){ *(s i) = *(t j); i ; j ; } }
В основном у меня были:
int main(){ char s[] = "Hola"; char t[] = "lala"; stringcat(s,t); printf("%sn", s); }
На первый взгляд я подумал, что это правильно, но фактический результат был Holalalaa
. Конечно, это был не тот результат, который я ожидал, но потом я закодировал это:
void stringcat(char *s, char *t){ int i,j; i = j = 0; while(*(s i) != ''){ printf("%d", i); i ; } while((*(s i) = *(t j)) != ''){ i ; j ; } }
И результат был правильным.
Но потом я много думал о первом коде, потому что он очень похож на второй, но почему первый вывод был неправильным?. Это как-то связано с утверждением while? или что-то с указателями?. Мне было действительно трудно понять, потому что вы не можете видеть, что происходит в массиве.
Большое спасибо.
Комментарии:
1. Вы получите переполнение массива, потому
char s[] = "Hola";
что в нем нет места для объединения. Вам будет легче читать, написав*(s i)
какs[i]
.2. @WeatherVane Я тоже думал об этом, но для этого я должен вернуть новый массив, верно? Или есть какой-либо способ использовать недействительную подпись?.
3. Кроме того, обратите внимание, что ваш первый фрагмент кода не копирует завершающий нулевой символ из
t
строки.4. Выделите для другого массива сумму двух длин 1 и верните ее из
char *stringcat(char *s, char *t)
5. @AdrianMole большое спасибо, я этого не заметил.
Ответ №1:
В вашем коде есть не одна проблема, которую вы обнаружили, но давайте начнем с нее.
На самом деле вы спрашиваете, почему
/* ... */ while ((*(t j)) != '') { *(s i) = *(t j); /* ... */
работает иначе, чем
/* ... */ while ((*(s i) = *(t j)) != '') { /* ... */
Я надеюсь, вы уже это видите, теперь, когда оба случая стоят бок о бок, фактически вертикально ;-). В первом случае значение t[j]
сравнивается до того, как оно будет скопировано s[i]
. Во втором случае сравнение выполняется после копирования. Вот почему во втором случае завершение копируется ''
в целевую строку, а в первом случае-нет.
Вывод, который вы получаете, работает случайно, это неопределенное поведение, так как вы пишете за пределами целевого массива. К счастью для вас, обе строки последовательно хранятся в памяти, и вы перезаписываете исходную строку ее собственными символами.
Поскольку ваш первый случай не копирует ''
, в конечном printf()
итоге выводится больше символов, пока ''
не будет найдено a. По случайности это последнее 'a'
.
Как отмечали другие, в целевой строке недостаточно места для объединенной строки. Предоставьте еще немного места, как это:
char s[10] = "Hola"; /* 10 is enough for both strings and the terminating ''. */
Однако, если бы вы уже сделали это, ошибка не была бы обнаружена, потому что последние 6 символов s
инициализируются с ''
помощью . Не копирование завершения ''
не имеет никакого значения. Вы можете увидеть это, если используете
char s[10] = "Holaxxxx";
Я не думаю, что ваше решение является ожидаемым. Вместо s[i]
того , чтобы вы используете *(s i)
, что по сути одно и то же, доступ к массиву. Рассмотрите возможность изменения s
(и, конечно же, t
) в функции и используйте just *s
.
Примечание: Функция printf()
в функции, скорее всего, является остатком отладки. Но я уверен, что ты знаешь.