Копирование элементов из одного массива символов в другой

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

#include<stdio.h>
#include<stdlib.h>

int main()
{
    char temp[100], str[100];
    fgets(str, 100, stdin);
    int i;
    for(i = 0; str[i]!='\0'; i++)
    {
        temp[i] = str[i];
    }
    puts(temp);
    return 0;
}

person Ranjan Srinivas    schedule 20.02.2016    source источник
comment
NULL — это макрос с константой нулевого указателя. Здесь это не имеет значения. Вы имеете в виду символ ASCII NUL или nul с целочисленным значением 0.   -  person too honest for this site    schedule 20.02.2016
comment
Читать о strcpy.   -  person Pete Becker    schedule 20.02.2016
comment
@Pete Becker Я думаю, что это, ОЧЕНЬ вероятно, будет чем-то вроде домашней работы / проблемы с учебным пособием (то есть предназначено / разработано для того, чтобы осознать проблемы с копированием строк). Простое указание кому-нибудь прочитать о strcpy не поможет добиться такого понимания.   -  person Tersosauros    schedule 20.02.2016
comment
@Tersosauros - новички часто создают свои собственные функции, потому что понятия не имеют, что находится в стандартной библиотеке.   -  person Pete Becker    schedule 20.02.2016
comment
@Ranjan Srinivas, когда вы запускали это, это было на машине с Linux (настоящей или виртуальной). Дополнительные сведения см. в этом ответе , но, по сути, ядро ​​​​Linux обнуляло память, поскольку она была новой (недавно выделенной). По сути, ваша программа случайно получила блок памяти, содержащий '\0', поэтому puts нашла NUL. Такое поведение НЕ гарантируется и (как говорят ответы) является неопределенным поведением.   -  person Tersosauros    schedule 20.02.2016
comment
@Pete Becker Верно, но мы не знаем, связано ли это с недостатком знаний (и необходимостью strcpy), или это студент, который, как ожидается, столкнется с (а) определенной проблемой (проблемами) - т.е. подготовиться к какому-то заданию или лекции и т.д.   -  person Tersosauros    schedule 20.02.2016
comment
@Tersosauros - да, и поэтому мой комментарий был комментарием, а не ответом.   -  person Pete Becker    schedule 20.02.2016
comment
Я думаю, что лучше использовать strdup, чем strcpy. Кроме того, использование != в цикле for меня немного смутило бы. Удобнее использовать во время...   -  person jamesqf    schedule 20.02.2016


Ответы (3)


Функция void puts(const char *) зависит от size_t strlen(const char *), и вывод этой функции undefined, если в переданный аргумент (см. этот ответ). Таким образом, в вашем случае strlen внутри puts, вероятно, нашел значение 0 "рядом" с вашим массивом в памяти, что привело к правильному поведению puts, однако это не всегда так, поскольку оно не определено.

person maciekjanusz    schedule 20.02.2016

Вот ввод и вывод на моем компьютере:

0
0
絯忐`

Process returned 0 (0x0)   execution time : 1.863 s
Press any key to continue.

Видишь мусор "絯忐`"? Это неопределенное поведение. Ваша программа работает хорошо, потому что вам (не)повезло.

Опять же, неопределенное поведение не заслуживает достаточного обсуждения.

person nalzok    schedule 20.02.2016
comment
Я собирался поставить +1, пока не прочитал последнюю строку: неопределенное поведение не заслуживает обсуждения. Хотя это правда, OP (не)повезло, как вы выразились, я думаю, что отказ от обсуждения неопределенного поведения означает неспособность правильно ответить на вопрос. - person Tersosauros; 20.02.2016
comment
Все и что угодно может произойти, когда имеет место неопределенное поведение. Как мудро отмечает K&R, если вы не знаете, как они выполняются на разных машинах, эта невинность может помочь вам защититься. Поэтому я думаю, что лучше не обсуждать неопределенное поведение. - person nalzok; 20.02.2016

Когда вы объявляете char temp[100] без какой-либо инициализации, он просто занимает неинициализированную память. Эта память может быть чем угодно. Например, следующая программа запишет начальное содержимое этого в виде целых чисел:

#include<stdio.h>
#include<stdlib.h>

int main()
{
    char temp[100];
    int i;
    for(i = 0; i < 100 ; i++)
    {
        fprintf(stdout, "%d ", temp[i]);
    }
    return 0;
}

Это печатает для меня постоянно разные выходные данные, хотя по какой-то случайности он продолжает печатать секции нулей. например.:

88 -70 43 81 -1 127 0 0 88 -70 43 81 -1 127 0 0 1 0 0 0 0 0 0 0 112 -70 43 81 -1 127 0 0 0 64 -108 14 1 0 0 0 72 50 -13 110 -1 127 0 0 -128 -70 43 81 -1 127 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 96 -70 43 81

88 90 72 88 -1 127 0 0 88 90 72 88 -1 127 0 0 1 0 0 0 0 0 0 0 112 90 72 88 -1 127 0 0 0 -96 119 7 1 0 0 0 72 18 72 105 -1 127 0 0 -128 90 72 88 -1 127 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 96 90 72 88

88 -6 -79 87 -1 127 0 0 88 -6 -79 87 -1 127 0 0 1 0 0 0 0 0 0 0 112 -6 -79 87 -1 127 0 0 0 0 14 8 1 0 0 0 72 34 57 104 -1 127 0 0 -128 -6 -79 87 -1 127 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 96 -6 -79 87

Скорее всего, ваша строка, не заканчивающаяся нулем, случайно завершается нулем в силу того факта, что temp[strlen(str)] по счастливой случайности является \0.

person yaakov    schedule 20.02.2016
comment
печать этих переменных является неопределенным поведением - person Giorgi Moniava; 20.02.2016
comment
@Giorgi Как так? Насколько я знаю, определено, что я получаю 100 байтов, но значения этих байтов не определены. Они должны быть безопасными для печати, но никогда не гарантируется, что они из себя представляют. - person yaakov; 20.02.2016
comment
Нет, пожалуйста, прочитайте о понятии неопределенного поведения. Чтение неинициализированных переменных — это UB. - person Giorgi Moniava; 20.02.2016
comment
char temp[100]; представляет собой массив char. Используйте спецификатор формата для char, чтобы напечатать их: fprintf(stdout, "%c ", temp[i]);. Спецификатор формата d хочет прочитать 4 байта. Спецификатор формата c читает только 1 байт. - person ryyker; 20.02.2016