Копирование части строки в C - PullRequest
6 голосов
/ 09 июня 2010

Кажется, это должно быть действительно просто, но по какой-то причине я не получаю его на работу.У меня есть строка с именем seq, которая выглядит следующим образом:

ala
ile
val

Я хочу взять первые 3 символа и скопировать их в другую строку.Я использую команду:

memcpy(fileName, seq, 3 * sizeof(char));

Что должно сделать fileName = "ala", верно?Но по какой-то причине я получаю fileName = "ala9".В настоящее время я работаю над этим, просто говоря fileName[4] = '\0', но мне было интересно, почему я получаю эти 9.

Примечание: после изменения seq на

ala
ile
val
ser

и повторного запускакод fileName становится "alaK".Уже не 9, но все же ошибочный персонаж.

Ответы [ 10 ]

18 голосов
/ 09 июня 2010

C использует нулевой терминатор для обозначения конца строки.memcpy не знает, что вы копируете строки (он просто копирует байты), поэтому он не думает надевать их.Обходной путь у вас на самом деле правильный ответ.

Edit: wolfPack88 имеет хороший момент.Вам действительно нужно изменить имя файла [3].Кроме того, приведенные ниже комментарии поднимают некоторые замечательные моменты о strncpy, который также стоит изучить.

11 голосов
/ 09 июня 2010

sprintf - ваш друг, который извлекает символы из середины одной строки и помещает их в буфер символов с нулевым окончанием.

sprintf(fileName, "%.3s", seq);

или

sprintf(fileName, "%.*s", 3, seq);

или даже

snprintf(fileName, sizeof(fileName), "%.*s", len, seq);

даст вам то, что вы хотите.Версия * допускает переменную длину, а snprintf безопаснее для избежания переполнения буфера

5 голосов
/ 09 июня 2010

Если вы хотите использовать memcpy для копирования строк, вы должны установить символ '\ 0' вручную после последнего символа строки.Если вы не хотите обрабатывать '\ 0' вручную, используйте вместо этого strcpy или strncpy.

5 голосов
/ 09 июня 2010

Вы должны использовать filename[3]='\0';.Что касается того, почему это необходимо: потому что ничто другое не установило терминатор NUL для строки, поэтому вам нужно.

Редактировать: конечно, для реального использования вы не используете константу, как я показал выше,Как правило, вы бы использовали что-то вроде:

char *substring(char *out, char const *in, size_t len) { 
    memcpy(out, in, len);
    out[len] = '\0';
    return out;
}

Обратите внимание, что у вас действительно была правильная идея, используя memcpy.strncpy (для очевидного примера) - не действительно правильная вещь, которую следует использовать для этой (или почти любой другой) цели.В списке стандартных библиотечных функций, которых следует избегать, strncpy стоит на втором месте в списке, уступая только gets (хотя, честно говоря, я должен отметить, что strtok является close третью).

Также обратите внимание, что (как и большинство стандартных библиотечных функций) здесь не делается попытка проверки передаваемых вами параметров - например, если вы скажете ему скопировать 99 символов из строки длиной всего 10 символов в буфердлина всего 5 символов, в любом случае он попытается скопировать 99 символов, что приведет к неопределенному поведению).

Edit2: одна альтернатива - использовать sprintf .

5 голосов
/ 09 июня 2010

Вам нужно установить

fileName[3] = 0;

Убедитесь, что fileName имеет достаточно места для конца байта NUL строки.

4 голосов
/ 09 июня 2010

Стандартная библиотека языка Си не имеет специальной функции для копирования части строки.Правильный способ сделать это - использовать memcpy (как вы уже сделали) и явно завершить результат нулем.Вы забыли завершить результат, поэтому после скопированной части строки вы видите странные дополнительные символы.

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

Иногда вы можете встретить примеры кода, которые пытаются использовать функцию strncpy для этой цели.Хотя в некоторых случаях это может показаться «работающим», абсолютно бесполезно использовать strncpy, учитывая, что он не предназначен для такого использования.

3 голосов
/ 09 июня 2010

Строки в C обнуляются, что означает, что вам нужен нуль-символ в конце строки.Похоже, вам повезло иметь нулевой символ сразу после следующего символа, так что вы получили только один дополнительный символ мусора, вы могли бы также получить тысячи символов мусора ...

2 голосов
/ 09 июня 2010

В дополнение к нулевой завершающей строке

fileName[3] = '\0';

Вы также можете рассмотреть возможность использования strncpy вместо memcpy. Кроме того, sizeof(char) всегда должно иметь значение 1, поэтому оно является избыточным.

Удачи!

2 голосов
/ 09 июня 2010

Неожиданный символ является артефактом неправильного завершения нуля fileName.

В этом случае fileName должен быть буфером char, длина которого не менее 4 (три для трех символов аля и один для завершающего нулевого символа).Чтобы установить нулевой символ, вы можете использовать:

fileName[3] = '\0';

после memcpy.

2 голосов
/ 09 июня 2010

Причина в том, что вы копируете трехсимвольные байты из seq, однако завершающего нулевого символа нет.Таким образом, вы можете обойти это не обходное решение, а правильное решение.

C-строки должны заканчиваться нулем.Если это не так, то «пользователь» строк читает, пока он не сможет читать дальше, что приводит к неопределенному поведению.

Кстати, почему бы не использовать strncpy?

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...