#c #segmentation-fault #buffer #memmove
#c #ошибка сегментации #буфер #memmove
Вопрос:
я пытаюсь скопировать два целых числа и символьную строку в буфер и распечатать элементы буфера. Я получаю ошибку seg для третьей инструкции printf:
id = 102;
len = 3;
str = "working";
memmove(buffer,amp;message_id,sizeof(id));
memmove(buffer (sizeof(id)),amp;len,sizeof(len));
memmove(buffer (2*sizeof(id)),amp;string, sizeof(str));
printf("1 is: %dn", buffer[0]);
printf("2 is: %dn", buffer[4]);
printf("3 is %sn, buffer[8])); // here is where i get the seg fault should
be a string
/***/
bufer is declared as unsinged char buffer[444];
Я не знаю, почему это приведет к ошибке seg?
Комментарии:
1. что такое буфер с двумя «f», объявленный как — вы говорите, bufer — это символ без знака [444]
2. Как объявляются string и str ?
Ответ №1:
buffer[8]
является a char
, %s
ожидает строки, что означает char *
вместо этого передачу amp;buffer[8]
. Ошибка сегментации возникает из-за того, что printf пытается обработать символ как указатель на символ, который является адресом (и если передается символ, он вряд ли будет допустимым)
РЕДАКТИРОВАТЬ: как прокомментировал Дэвид, если отправная точка для копирования строки связана со значениями перед ней, не используйте фиксированное значение, вместо amp;buffer[8]
использования buffer (2*sizeof(id))
или buffer[2*sizeof(id)]
Комментарии:
1. 1, хотя
buffer 8
или еще лучшеbuffer 2*sizeof (int)
было бы предпочтительнее
Ответ №2:
В вашем коде было несколько проблем, но наиболее важным моментом является то, что memmove()
не копируется нулевой символьный байт строки.
Функция не проверяет наличие какого-либо завершающего нулевого символа в исходном коде — она всегда копирует ровно num байт.
Это дает вам два варианта:
- Учитывайте это при копировании материала:
memmove(buffer sizeof(id) sizeof(len), str, strlen(str) 1);
- Или после того, как память была скопирована, убедитесь, что строка заканчивается на
''
(иначе.0
) в вашем буфере:
memmove(buffer sizeof(id) sizeof(len), str, strlen(str));
buffer[sizeof(id) sizeof(len) strlen(str) 1] = 0;
В любом случае, код теперь работает. Другая проблема заключалась в том, что вы пытались указать длину строки с помощью sizeof(str)
. Это неправильно, и вы должны это делать strlen(str)
. И последнее, чего в целях наглядности и безопасности не делайте 2*sizeof(id)
. Если позже вы решите изменить тип переменной, вы облажались. Правильный путь был бы sizeof(id) sizeof(len)
. Вот и все.
int id = 102;
int len = 3;
char* str = "working";
char buffer[444];
memmove(buffer,amp;id,sizeof(id));
memmove(buffer (sizeof(id)), amp;len, sizeof(len));
memmove(buffer sizeof(id) sizeof(len), str, strlen(str));
buffer[sizeof(id) sizeof(len) strlen(str) 1] = 0;
printf("1 is: %dn", buffer[0]);
printf("2 is: %dn", buffer[4]);
printf("3 is: %sn", amp;buffer[8]);
Комментарии:
1. отличное объяснение. Большое спасибо. я забыл использовать strlen и учитывать нулевой символ
Ответ №3:
Основная проблема заключается в том, что вы пытаетесь напечатать строку, передавая только символ. Это потому, что buffer[8]
ссылается на char
с индексом 8, а не на строку, начинающуюся с этой позиции. Итак, вам нужно взять адрес buffer[8]
, чтобы превратить его в строку или char*
.
Причина, по которой происходит сегментация, заключается в том, что printf
пытается напечатать строку, начинающуюся с адреса, указанного первым символом (т.Е. само содержимое строки), которое не является допустимым указателем.
Также имеется ряд опечаток и ошибок. Рабочая версия приведена ниже:
#include <stdio.h>
#include <memory.h>
int main()
{
unsigned char buffer[444];
int id = 102;
int len = 3;
char* str = "working";
memmove(buffer,amp;id,sizeof(id));
memmove(buffer (sizeof(id)),amp;len,sizeof(len));
memmove(buffer (2*sizeof(id)), str, sizeof(str));
printf("1 is: %dn", buffer[0]);
printf("2 is: %dn", buffer[4]);
printf("3 is %sn", amp;buffer[8]);
return 0;
}
Если вы скомпилировали это приложение со всеми включенными предупреждениями (т.Е. -Wall
), ваш компилятор (по крайней мере, GCC) должен предупредить вас о вашей ошибке следующим образом:
problem.c:18: warning: format ‘%s’ expects type ‘char *’, but argument 2 has type ‘int’
Предупреждения не следует игнорировать!