2012-09-04 3 views
1

Я хотел бы знать, как результат memcpy() относительно распределения памяти.Распределение памяти массива Char

#include<stdio.h> 
#include<string.h> 

typedef struct { 
    char myname[7] ; 
} transrules; 

trans typedef struct { 
    char ip ; 
    int udp; 
    transrules rules[256]; 
} __attribute__ ((__packed__)) myudp; 

myudp __attribute__ ((__packed__)) udpdata ; 

char arr[400] ; 

int main() {    
    memset (&udpdata , 0 ,sizeof(udpdata)); 
    udpdata.ip = 'a' ; 
    udpdata.udp = 13 ; 
    udpdata.rules[0].myname = "lalla\0" ; 
    memcpy (&arr , &udpdata, sizeof(udpdata)); 
    printf("%c",arr[0]); 
    return 0; 
} 

Что касается кода, как мы выводим из массива символов в структуре transrules?

PS: Да, этот код вызывает ошибку, sheesh char!

Как определено в массиве типа char, почему arr [1] все еще принимает целочисленное значение с memcpy()?

+0

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

ответ

3

memcpy не выделяет никакой памяти. В вашем вызове memcpy память для адресата arr была выделена, когда была определена переменная arr (char arr[400]).

Там есть проблема, которая заключается в том, что вы не выделили достаточно места. Вы копируете sizeof(updata) байтов в arr, что, вероятно, 1 + 4 + 7 * 256 = 1797 (это может различаться в зависимости от sizeof(int) и от того, действительно ли __packed__ не использует все неиспользуемые байты на вашей платформе). Если вам действительно нужно arr (вы, вероятно, нет), сделайте его как минимум sizeof(updata) большим. Определение его char arr[sizeof(updata)] в порядке.

Если макет структуры определен каким-либо внешним форматом, вы должны использовать тип фиксированного размера вместо int (который составляет 2 или 4 байта в зависимости от платформы и может быть других размеров, но вы вряд ли чтобы встретить их).

Если макет структуры определен каким-то внешним двоичным форматом, и вы хотите распечатать 1797 байт в этом формате, используйте fwrite.

fwrite(updata, sizeof(updata), 1, stdout); 

Если вы хотите иметь человеческое представление данных, используйте printf с соответствующими спецификациями формата.

printf("ip='%c' udp=%d\n", updata.ip, updata.ip); 
for (i = 0; i < sizeof(updata.rules)/sizeof(updata.rules[0]); i++) { 
    puts(updata.rules[i].myname); 
} 

Несмотря на название, char фактически тип байтов. Для символов в C. не существует отдельного типа. Символьная константа, такая как 'a', фактически является целым значением (97 почти для всех систем, согласно ASCII). Это похоже на запись putchar или printf("%c", …), которые делают байт интерпретированным как символ.

Если ваш компилятор не сигнализирует об ошибке, когда вы смешиваете вверх указатель (например, char*) с целым числом, с другой стороны, повернуть вверх уровень предупреждения. С Gcc используйте как минимум gcc -O -Wall.


После фактически компиляции кода, я вижу основную ошибку (вы должны иметь копию вставили сообщение об ошибке от компилятора в вашем вопросе):

udpdata.rules[0].myname = "lalla\0" ; 

udpdata.rules[0].myname представляет собой массив байтов. Вы не можете назначить массив на C. Вам нужно скопировать элементы по одному. Поскольку это массив из char, и вы хотите скопировать в него строку, вы можете использовать strcpy для копирования всех байтов строки. Для кучи байтов в целом вы должны использовать memcpy.

strcpy(udpdata.rules[0].myname, "lalla"); 

(Обратите внимание, что "lalla\0" эквивалентно "lalla", все строковые литералы нулем в C.¹) Поскольку strcpy не выполняет проверку размера, вы должны убедиться, что строка (в том числе его завершающего нулевого символа) помещается в память, которую вы выделили для целей. Вы можете использовать другие функции, такие как strncat или strlcpy, если вы хотите указать максимальный размер.

¹ Существует одно исключение (и только это исключение), где "lalla" не будет иметь нулевое завершение: при инициализации массива из 5 байтов, например. char bytes[5] = "lalla". Если размер массива не менее 6 или не задан, будет завершающий нулевой байт.

+0

+1 Очистить пояснения :) – user1471

1
 
// this is really bad 
udpdata.rules[0].myname = "lalla\0" ; 

// do this instead. You want the literal string in your field. 
memcpy(udpdata.rules[0].myname, "lalla\0", 6); 

.... 

// This is wrong. arr is already a pointer. 
memcpy (&arr , &udpdata, sizeof(udpdata)); 

// do this instead 
mempcy (arr, &udpdata, sizeof(udpdate)); 

Что касается печати, я не знаю, насколько большой Интс на вашей машине, но если они 4 байта, то

printf("%.7s", &arr[1+4]);

Я не знаю, почему вы хотите, чтобы преобразовать все в массив символов, если вы хотите распечатать содержимое. Просто используйте struct и a для цикла. В любом случае, я думаю, вы можете прочитать на C массивах.

1

Что касается кода, как мы печатаем массив символов в структуре transrules?

/* incorrect -> udpdata.rules[0].myname = "lalla\0" ; */ 
strcpy(udpdata.rules[0].myname,"lalla") ; 
printf("%s\n",udpdata.rules[0].myname); 

Как массив определен имеет тип полукокса почему обр [1] по-прежнему принимать целочисленное значение с тетсру?

memcpy не знает и не заботится о том, какие базовые типы данных могут быть там, где они копируются. Он принимает Void указатели и копирует значение в один или несколько байт на один или несколько других байтов:

void * memcpy (void * destination, const void * source, size_t num); 
Смежные вопросы