ANSI C strncpy искажает вывод на экран и значения других переменных

При использовании ANSI C экран искажается после strncpy. Также, если я попытаюсь напечатать любые значения переменных int, они станут неверными. Однако, если я передвину строку печати до strncpy, все будет в порядке.

Кто-нибудь знает, почему?

#define TICKET_NAME_LEN 40

struct stock_data 
{
    char ticket_name[TICKET_NAME_LEN+1];
};

struct stock_data user_input;

char tname[TICKET_NAME_LEN+1] = "testing it";

strncpy(user_input.ticket_name, tname, TICKET_NAME_LEN);

person Oscar    schedule 09.11.2013    source источник
comment
скорее всего проблема в коде, который вы не показываете.   -  person AndersK    schedule 09.11.2013
comment
остальная часть кода связана с несколькими файлами заголовков и c. Я упростил код и разместил его. Что-то не так с buffer и strncpy, но я не мог понять.   -  person Oscar    schedule 09.11.2013
comment
код, который вы показали, выглядит нормально, возможно, вы могли бы показать, как вы распечатываете строки.   -  person AndersK    schedule 09.11.2013
comment
Удаление ненужного и несвязанного кода — это прекрасно, но когда вы это делаете, удаляйте все, чтобы у вас остался короткий, полный, компилируемый пример, демонстрирующий проблему. Тот факт, что у вас есть эта проблема, показывает, что вы, вероятно, еще не в состоянии определить, что в коде ее вызывает, поэтому публикация чего-то компилируемого, демонстрирующего проблему, - это единственный способ узнать, что вы не оставили важный код вышел.   -  person Crowman    schedule 09.11.2013
comment
Узнайте, как создать SSCCE (Короткий, автономный, правильный пример), который воспроизводит проблему и не содержать ничего лишнего. Безжалостное удаление кода, сокращение нескольких тысяч строк до 30, которые инкапсулируют проблему, может быть довольно забавным занятием.   -  person Jonathan Leffler    schedule 09.11.2013


Ответы (1)


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

Единственная возможная проблема с кодом, который вы показываете, заключается в том, что strncpy() не гарантирует, что выходная (целевая) строка завершается нулем. Это не повредит с показанным кодом (он не делает ничего плохого), но другой код, который ожидает, что строка будет завершаться нулем, который беспечно копирует ее, не гарантируя, что есть место, может попирать другую память, потому что строка не является нулевой прекращено.

Если входная (исходная) строка длиннее указанного пробела (в данном случае больше, чем TICKET_NAME_LEN в байтах), то user_input.ticket_name не будет заканчиваться нулем, кроме как случайно. Если он короче, то user_input.ticket_name будет дополнен нулем до длины TICKET_NAME_LEN байт.

Если это проблема, очень простое решение — добавить строку:

user_input.ticket_name[TICKET_NAME_LEN] = '\0';

после (или даже до, но традиционнее делать это после) strncpy().

Однако, чтобы столкнуться с этой проблемой, вам нужно попытаться скопировать имя из 41 или более символов в элемент имени билета структуры.

Скорее всего, причина вашей беды в чем-то другом.

ISO/IEC 9899:2011 §7.24.2.4 Функция strncpy

¶2 Функция strncpy копирует не более n символов (символы, следующие за нулевым символом, не копируются) из массива, на который указывает s2, в массив, на который указывает s1.308) Если происходит копирование между объектами, которые перекрываются, поведение не определено.

¶3 Если массив, на который указывает s2, является строкой, которая короче n символов, нулевые символы добавляются к копии массива, на который указывает s1, до тех пор, пока не будет записано n символов.

308) Таким образом, если в первых n символах массива, на который указывает s2, нет нулевого символа, результат не будет заканчиваться нулем.

person Jonathan Leffler    schedule 09.11.2013
comment
но более привычно делать это после -- потому что таким образом вы знаете, что буфер завершается нулем (и потенциально теряется последний символ) по сравнению с неверными числами в strncpy, и случайно удалил нулевой терминатор. - person Roger Lipscombe; 09.11.2013