скопировать символьную строку в неподписанный буфер: ошибка сегментации - PullRequest
0 голосов
/ 28 апреля 2011

Я пытаюсь скопировать два целых числа и строку символов в буфер и распечатать элементы буфера. Я получаю ошибку сегмента для третьего оператора printf:

    id = 102;
    len = 3;
    str = "working";
    memmove(buffer,&message_id,sizeof(id));
    memmove(buffer+(sizeof(id)),&len,sizeof(len));
    memmove(buffer+(2*sizeof(id)),&string, sizeof(str));

    printf("1 is: %d\n", buffer[0]);
    printf("2 is: %d\n", buffer[4]);
    printf("3 is %s\n, buffer[8])); // here is where i get the seg fault should
    be a string
    /***/
    bufer is declared as unsinged char buffer[444];

Я не знаю, почему это вызвало ошибку?

Ответы [ 3 ]

4 голосов
/ 28 апреля 2011

buffer[8] - это char, %s ожидает строку, что означает char *, вместо этого передайте &buffer[8]. Вы получаете ошибку сегментации, потому что printf пытается обработать char как указатель на char , который является адресом (и если символ передается, он вряд ли будет действительным)

РЕДАКТИРОВАТЬ: как прокомментировал Дэвид , если начальная точка для копирования строки связана со значениями до нее, не используйте фиксированное значение вместо &buffer[8] используйте buffer+(2*sizeof(id)) или buffer[2*sizeof(id)]

1 голос
/ 28 апреля 2011

В вашем коде было несколько проблем, но наиболее важным моментом является то, что memmove() не копирует нулевой символьный байт строки.

Функция не проверяет наличие какого-либо завершающего нулевого символа в источнике - она ​​всегда копирует ровно num байтов.

Это дает вам два варианта:

  • Учтите это, пока вы копируете материал:

memmove(buffer+sizeof(id)+sizeof(len), str, strlen(str) +1);

  • Или после того, как память была скопирована, убедитесь, что строка заканчивается символом '\0' (он же. 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,&id,sizeof(id));
memmove(buffer+(sizeof(id)), &len, sizeof(len));
memmove(buffer+sizeof(id)+sizeof(len), str, strlen(str));
buffer[sizeof(id)+ sizeof(len) + strlen(str) + 1] = 0;

printf("1 is: %d\n", buffer[0]);
printf("2 is: %d\n", buffer[4]);
printf("3 is: %s\n", &buffer[8]);
1 голос
/ 28 апреля 2011

Основная проблема в том, что вы пытаетесь напечатать строку, передавая только символ. Это потому, что buffer[8] относится к char в индексе 8, а не к строке, начинающейся в этой позиции. Таким образом, вам нужно взять адрес buffer[8], чтобы сделать его строкой или char*.

Причина, по которой он segfaults, заключается в том, что printf пытается напечатать строку, начинающуюся с адреса, указанного первым символом (т. Е. Самого содержимого строки), который не является допустимым указателем.

Есть также несколько опечаток и ошибок. Рабочая версия ниже:

#include <stdio.h>
#include <memory.h>

int main()
{
    unsigned char buffer[444];
    int id = 102;
    int len = 3;
    char* str = "working";

    memmove(buffer,&id,sizeof(id));
    memmove(buffer+(sizeof(id)),&len,sizeof(len));
    memmove(buffer+(2*sizeof(id)), str, sizeof(str));

    printf("1 is: %d\n", buffer[0]);
    printf("2 is: %d\n", buffer[4]);
    printf("3 is %s\n", &buffer[8]);

    return 0;
}

Если вы скомпилировали это приложение со всеми включенными предупреждениями (т.е. -Wall), ваш компилятор (по крайней мере, GCC делает) должен предупредить вас о вашей ошибке, например:

problem.c:18: warning: format ‘%s’ expects type ‘char *’, but argument 2 has type ‘int’

Предупреждения не следует игнорировать!

...