Копирование части строки в C

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

ala
ile
val

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

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

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

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

ala
ile
val
ser

и повторно выполняя тот же код, имя файла становится "alaK". Не 9 больше, но все еще ошибочный символ.

6
задан sth 8 June 2010 в 22:04
поделиться

10 ответов

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

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

18
ответ дан 8 December 2019 в 02:03
поделиться

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

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

fileName[3] = '\0';

после memcpy.

2
ответ дан 8 December 2019 в 02:03
поделиться

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

5
ответ дан 8 December 2019 в 02:03
поделиться

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

3
ответ дан 8 December 2019 в 02:03
поделиться

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

fileName[3] = '\0';

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

Удачи!

2
ответ дан 8 December 2019 в 02:03
поделиться

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

fileName[3] = 0;

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

5
ответ дан 8 December 2019 в 02:03
поделиться

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

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

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

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

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

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

5
ответ дан 8 December 2019 в 02:03
поделиться

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

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

или

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

или даже

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

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

.
11
ответ дан 8 December 2019 в 02:03
поделиться

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

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

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

4
ответ дан 8 December 2019 в 02:03
поделиться

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

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

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

2
ответ дан 8 December 2019 в 02:03
поделиться
Другие вопросы по тегам:

Похожие вопросы: