Функция копированя строк

Чем отличается этот код:

void copy(char* to, char* from){
    int i;
    i = 0;
    while((to[i] = from[i]) != '\0')
        i++;
}

от этого:

void copy(char* to, char* from){
    int i;
    for(i = 0; from[i] != '\0'; i++)
        to[i] = from[i];
}

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

Если что, вот полный код по нахождению максимальной длинной строки в потоке (с первым вариантом функции копирования):

#include <stdio.h>

#define MAXLINE 1000


int getline(char* str, int max){
    int c, i;
    for(i = 0; i < max - 1 && (c = getchar()) != EOF && c != '\n'; ++i)
        str[i] = c;

    if(c == '\n'){
        str[i] = c;
        i++;
    }
    str[i] = '\0';
    return i;
}
void copy(char* to, char* from){
    int i;
    i = 0;
    while((to[i] = from[i]) != '\0')
        i++;
}
int main(void)
{
    int size;
    int max = 0;
    char in[MAXLINE];
    char from[MAXLINE];

    while((size = getline(from, MAXLINE)) > 0)
        if(size > max){
            max = size;
            copy(in, from);
        }
    if(max > 0)
        printf("%s",in);

    return 0;
}

Ответы (3 шт):

Автор решения: Solt

Кажется, что всё-таки цикл с while работает корректней, а второй - с мусором. Причина в том, что в while последний '\0' перекладывается в массив до проверки, а во втором случае при нахождении нуля происходит выход из цикла без перекладывания. Итог - строка не содержит конца.

Можно исправить так:

void copy(char* to, char* from){
    int i;
    for(i = 0; (to[i] = from[i]) != '\0'; i++);
}

А я бы ещё для надёжности добавил перед выводом in[MAXLINE-1]=0; Это исключит вероятность доступа к невыделенной памяти.

→ Ссылка
Автор решения: Harry

Строка - это не только текст, но и завершающий нулевой символ. Который тоже надо копировать.

Короче всего так, без всяких индексов:

void copy(char* to, char* from)
{
    while(*to++ = *from++);
}

Ну, или, что то же самое,

void copy(char* to, char* from)
{
    for(;*to++ = *from++;);
}
→ Ссылка
Автор решения: Stanislav Volodarskiy

Первый код

void copy(char* to, char* from){
    int i;
    i = 0;
    while((to[i] = from[i]) != '\0')
        i++;
}

Заменяем равносильным кодом по правилу
while (C) B;while (true) { if (!(C)) break; B; }:

void copy(char* to, char* from){
    int i;
    i = 0;
    while(true) {
        if(!((to[i] = from[i]) != '\0'))
            break;
        i++;
    }
}

Присвоение внутри if выносим перед ним:

void copy(char* to, char* from){
    int i;
    i = 0;
    while(true) {
        to[i] = from[i];
        if(!(from[i] != '\0'))
            break;
        i++;
    }
}

Второй код

void copy(char* to, char* from){
    int i;
    for(i = 0; from[i] != '\0'; i++)
        to[i] = from[i];
}

Первое выражение из for выносится перед ним, третье выражение в конец цикла:

void copy(char* to, char* from){
    int i;
    i = 0;
    for(; from[i] != '\0';) {
        to[i] = from[i];
        i++;
    }
}

for без первого и третьего выражений равносилен while:

void copy(char* to, char* from){
    int i;
    i = 0;
    while(from[i] != '\0') {
        to[i] = from[i];
        i++;
    }
}

while разбираем в конструкцию while/if, как раньше:

void copy(char* to, char* from){
    int i;
    i = 0;
    while(true) {
        if(!(from[i] != '\0'))
            break;
        to[i] = from[i];
        i++;
    }
}

Сравнение

Теперь два кода можно сравнить бок о бок. И видно что условие выхода из цикла и копирование символа поменялись местами:

Первый код Второй код
void copy(char* to, char* from){
int i;
i = 0;
while(true) {
to[i] = from[i];
if(!(from[i] != '\0'))
break;
i++;
}
}
void copy(char* to, char* from){
int i;
i = 0;
while(true) {
if(!(from[i] != '\0'))
break;
to[i] = from[i];
i++;
}
}
Копирует все символы строки
и завершающий '\0'.
Копирует все символы строки
без завершающего '\0'.

Правка

Поправить второй код можно так:

void copy(char* to, char* from){
    int i;
    for(i = 0; from[i] != '\0'; i++)
        to[i] = from[i];
    to[i] = '\0'; // дописываем забытый ноль
}
→ Ссылка