C странное поведение массива

После изучения этого оба strncmp не то, что это, кажется, и strlcpy не будучи доступным в моей операционной системе (Linux), я полагал, что мог попытаться записать это сам.

Я нашел кавычку от Ulrich Drepper, 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 на данный момент я зафиксирую это позже).

Но почему там внешнее содержание массива (от строки формата) в моем месте назначения? Это - как будто место назначения было на самом деле ИЗМЕНЕНО для соответствия новой длине.

6
задан LukeN 14 May 2010 в 18:54
поделиться

4 ответа

Конец строки отмечается символом \0 память после него может быть любой, если только ваша ОС специально не очистит ее, тогда это будет просто любой случайный мусор, который там остался.

Обратите внимание, что в этом случае "проблема" не в copy_string, вы точно копируете 10 символов - но память после 'first' в вашем основном коде просто случайна.

4
ответ дан 17 December 2019 в 00:05
поделиться

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

Вы можете легко увидеть, что вы копируете исходную строку с ее нулевым терминатором. Но поскольку вы копируете 10 байт, а обе строки "First" и "Second" короче 10 байт, вы также копируете лишние байты мимо них.

2
ответ дан 17 December 2019 в 00:05
поделиться

Использование memcpy(dest, src, n-1) вызывает неопределенное поведение, если dest и src не имеют длины не менее n-1.

Например, First\0 имеет длину шесть символов, но вы читаете из него n-1 (9) символов; содержимое памяти после конца строкового литерала не определено, как и поведение вашей программы при чтении этой памяти.

1
ответ дан 17 December 2019 в 00:05
поделиться

Дополнительный «материал» есть, потому что вы передали размер буфера в memcpy . Он скопирует такое количество символов, даже если исходный код короче.

Я бы поступил немного по-другому:

void copy_string(char *dest, char const *src, size_t n) { 
    *dest = '\0';
    strncat(dest, src, n);
}

В отличие от strncpy , strncat определен так, чтобы работать так, как большинство людей разумно ожидало бы.

0
ответ дан 17 December 2019 в 00:05
поделиться
Другие вопросы по тегам:

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