calloc и копирование данных в область памяти с помощью c - PullRequest
2 голосов
/ 03 февраля 2010

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

Спасибо.

#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));

Ответы [ 4 ]

5 голосов
/ 03 февраля 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] более полезно, чем кажется.

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

2 голосов
/ 03 февраля 2010

Попробуйте:

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 +
2 голосов
/ 03 февраля 2010
printf("bufptr22: %d\n", *bufptr+sizeof(int));

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

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

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

0 голосов
/ 03 февраля 2010

Это:

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

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

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

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

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

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

...