C Странное поведение массива
Вопрос
После изучения того, что оба strncmp
не то, что это кажется и strlcpy
Не доступен в моей операционной системе (Linux), я полагал, что могу попытаться написать это сам.
Я нашел цитату из Ульриха Дразма, сопровождающего Libc, который публикул альтернативу strlcpy
с использованием mempcpy
. Отказ У меня нет mempcpy
Либо, но это поведение было легко реплицироваться. В первую очередь, это тестовый камень, у меня есть
#include <stdio.h>
#include <string.h>
#define BSIZE 10
void insp(const char* s, int n)
{
int i;
for (i = 0; i < n; i++)
printf("%c ", s[i]);
printf("\n");
for (i = 0; i < n; i++)
printf("%02X ", s[i]);
printf("\n");
return;
}
int copy_string(char *dest, const char *src, int n)
{
int r = strlen(memcpy(dest, src, n-1));
dest[r] = 0;
return r;
}
int main()
{
char b[BSIZE];
memset(b, 0, BSIZE);
printf("Buffer size is %d", BSIZE);
insp(b, BSIZE);
printf("\nFirst copy:\n");
copy_string(b, "First", BSIZE);
insp(b, BSIZE);
printf("b = '%s'\n", b);
printf("\nSecond copy:\n");
copy_string(b, "Second", BSIZE);
insp(b, BSIZE);
printf("b = '%s'\n", b);
return 0;
}
И это его результат:
Buffer size is 10
00 00 00 00 00 00 00 00 00 00
First copy:
F i r s t b =
46 69 72 73 74 00 62 20 3D 00
b = 'First'
Second copy:
S e c o n d
53 65 63 6F 6E 64 00 00 01 00
b = 'Second'
Вы можете видеть во внутреннем представлении (линии insp()
создан) что есть немного шума, как printf()
Формат строки в проверке после первой копии и иностранного 0x01 во второй копии.
Строки скопированы натуральные и правильно обрабатывают слишком длинные источники (давайте игнорируем возможный вопрос с прохождением 0 как длина copy_string
На данный момент я исправлю это позже).
Но почему есть содержимое иностранного массива (из строки формата) внутри моего пункта назначения? Это так, как будто место назначения фактически изменена для соответствия новой длине.
Решение
Конец строки отмечен a 0 памятью после того, как это может быть что-нибудь, если только ваша ОС не заготовит его, то это просто что-то, что не осталось там.
Примечание. В этом случае «проблема» не в файле copy_String, вы точно копируете 10chars - но память после «первого» в вашем основном коде является просто случайным.
Другие советы
Поскольку вы не останавливаетесь в размере источника, вы останавливаетесь в размере судьбы, что происходит больше источника, поэтому вы копируете исходную строку плюс немного мусора.
Вы можете легко увидеть, что вы копируете исходную строку с его нулевым терминатором. Но так как вы memcopying 10 байтов, и оба строки "сначала" и "второе", короче 10 байтов, вы также копируете дополнительные байты мимо них.
Использование memcpy(dest, src, n-1)
вызывает неопределенное поведение, если dest
а также src
не оба по крайней мере n-1
в длину.
Например, First\0
в длину шесть символов, но вы читаете n-1
(9) символы из него; Содержимое памяти промирает конец строкового литерала неопределен, как и поведение вашей программы при прочтении этой памяти.
Дополнительные «вещи» там, потому что вы пропустили размер буфера на memcpy
. Отказ Он собирается скопировать, что многие персонажи, даже когда источник короче.
Я бы сделал вещи немного по-другому:
void copy_string(char *dest, char const *src, size_t n) {
*dest = '\0';
strncat(dest, src, n);
}
В отличие от strncpy
, strncat
определяется для работы, как большинство людей разумно ожидают.