calloc и копирование данных в область памяти с помощью c

Я пытаюсь выделить блок памяти, а затем скопировать данные в это пространство. Я сделал эту простую программу, и она не делает того, что я от нее ожидаю. Может ли кто-нибудь указать на мои ошибочные рассуждения.

Спасибо.

#include <stdio.h>
#include <stdlib.h>

void main(void)
{
int t1 = 11;
int t2 = 22;
int *bufptr;

bufptr = calloc(2, sizeof(int));
if(bufptr == NULL)
{
    fprintf(stderr, "Out of memory, exiting\n");
    exit(1);
}

memcpy(bufptr, &t1, sizeof(int));
memcpy((bufptr+sizeof(int)), &t2, sizeof(int));

printf("bufptr11: %d\n", *bufptr);
printf("bufptr22: %d\n", *bufptr+sizeof(int));
}

Он выводит следующее:
bufptr11: 11
bufptr22: 15 (это должно быть 22, а не 15)

Всем спасибо за помощь, но я только что столкнулся с очередной загвоздкой! Весь смысл этого упражнения в том, чтобы отправить некоторые данные через udp на другой хост. Я просматриваю содержимое bufptr перед вызовом sendto(), все выглядит нормально, и отправка проходит успешно. С другой стороны (я запускаю клиент/сервер на 127.0.0.1) я просто получаю "дерьмо". Я вызываю recvfrom(s_fd, bufptr, buflen и т. д.). Я использую тот же вызов calloc для выделения памяти для bufptr. Этот вызов возвращает нужное количество данных, но все это просто мусор!

bufptr = calloc(2, sizeof(int));
if(bufptr == NULL)
{
   fprintf(stderr, "Out of memory, exiting\n");
   exit(1);
}

buflen = 2*sizeof(int);

rc = recvfrom(sd, bufptr, buflen, 0, (struct sockaddr *)&serveraddr, &serveraddrlen);
printf("t2: %d\n", *bufptr);
printf("t3: %d\n", *(bufptr+1));

person NomadAlien    schedule 03.02.2010    source источник
comment
К вашему сведению, функция main возвращает int. Всегда. Все остальное может привести к неопределенному поведению. Возможно, это ваша проблема. ;-)   -  person Thomas Matthews    schedule 03.02.2010


Ответы (4)


Попробуйте эти:

memcpy(bufptr, &t1, sizeof(int)); // copy 11 into the first element of the array.
memcpy(bufptr+1, &t2, sizeof(int)); // bufptr+1 will point to the next int of the array.

printf("bufptr11: %d\n", *bufptr);
printf("bufptr22: %d\n", *(bufptr+1)); // parenthesis needed as * has higher precedence than +
person codaddict    schedule 03.02.2010

printf("bufptr22: %d\n", *(bufptr+sizeof(int)));

РЕДАКТИРОВАТЬ: Гораздо более коварным, чем скобки, является тот факт (который я, очевидно, сначала пропустил), что вы на самом деле переусердствуете с арифметикой указателя. Компилятор уже настраивает bufptr + x на bufptr + (x * sizeof(int)) байт. Поэтому, когда вы делаете bufptr + sizeof(int), вы фактически превышаете выделенную память.

Вы можете увидеть это с помощью:

printf("bufptr: %p\n", bufptr);
printf("bufptr + sizeof(int): %p\n", bufptr + sizeof(int));

Например. для меня (32-битная машина) выводит:

bufptr: 0x876f008
bufptr + sizeof(int): 0x876f018

16 байт разделено, когда я выделил всего 8! Напоминание, чем bufptr[1], полезнее, чем кажется.

Это своего рода ужасная ошибка, которая часто не проявляется сначала, а затем начинает вызывать сбои, когда вы изменяете несвязанный код. valgrind поймает его.

person Matthew Flaschen    schedule 03.02.2010
comment
Очень интересно, не знал об этом! Спасибо, Мэтью! - person NomadAlien; 03.02.2010

printf("bufptr22: %d\n", *bufptr+sizeof(int));

Это интерпретируется как (*bufptr) + sizeof(int). Что дает вам 11 + 4, чтобы получить 15, которые вы видите.

printf("bufptr22: %d\n", *(bufptr+sizeof(int)));

Это то, что вам нужно, если вы пытаетесь вернуть 22.

person rjp    schedule 03.02.2010

Этот:

memcpy((bufptr+sizeof(int)), &t2, sizeof(int));

неверно, так как, когда вы добавляете к указателю, вы добавляете в единицах размер типа, на который указывает указатель. В данном случае int. Так что нет необходимости задействовать sizeof, просто используйте количество "объектов" (ints) напрямую:

memcpy(bufptr + 1, &t2, sizeof(int));

Кроме того, лучше использовать указатель, а не повторять имя типа, это защитит вас, если оно изменится в будущем:

memcpy(bufptr + 1, &t2, sizeof *bufptr);

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

person unwind    schedule 03.02.2010