Доступ к полям массивов структур на Си - в чем ошибка?
Не могу понять, в чем ошибка
Есть структура, определенная через тип:
typedef struct _PARAMDESC { // описание параметров struct { int a; int b; int c; int d; int e; int f; } in; // для ввода struct { int a; int b; int c; int d; int e; int f; } out; // для вывода } PARAMDESC;В ОЗУ выделяется память под массив
PARAMDESC params[256]Есть еще одна структура, определенная через тип:
typedef struct _CONTEXT { // описание контекста вызова int error; // причина ошибки (в т.ч. системный код ошибки) int id; // идентификатор объекта PARAMDESC (*param)[256]; // указатель на массив параметров } CONTEXT;Есть переменная
CONTEXT ct, на этапе инициализации которой в ее полеct.paramзаносится указатель на массивPARAMDESC params[256]:ct.param=¶ms
Как правильно доступиться к полю in.a элемента массива params с индексом 1 через структуру ct?
Пробую так:
ct.param[1]->in.a
Компилятор не ругается, но указатель вычисляет неправильно. Под отладчиком вижу, что он берет содержимое ct.param (т.е. указатель на динамический блок памяти) и прибавляет к нему произведение индекса (1) на 12288, что ровно в 256 раз больше размера структуры PARAMDESC (48 байт). Т.е. за
1 элемент в данном случае он понимает весь массив из 256 структур, а не отдельный экземпляр структуры в этом массиве.
Что я не так указал при определении структур или при обращении к полю in.a элемента params[1]?
Воспроизводимый пример проблемы:
#include <stdlib.h>
typedef struct _PARAMDESC { // описание параметров
struct {
int a;
int b;
int c;
int d;
int e;
int f;
} in; // для ввода
struct {
int a;
int b;
int c;
int d;
int e;
int f;
} out; // для вывода
} PARAMDESC;
typedef struct _CONTEXT { // описание контекста вызова
int error; // причина ошибки (в т.ч. системный код ошибки)
int id; // идентификатор объекта
PARAMDESC (*param)[256]; // указатель на массив параметров
} CONTEXT;
int main()
{
CONTEXT ct;
ct.param=calloc(256,sizeof(PARAMDESC));
if (!ct.param) return 1;
ct.param[1]->in.a=0x5555; // Здесь ошибка!!!
// Происходит запись по смещению +0x3000 от
// начала массива, а ожидается запись по
// смещению +0x30 байт от начала массива
free(ct.param);
return 0;
}
Ответы (2 шт):
Так если param это указатель на массив, то и пишите правильно - вначале разыменовываем, а потом индексируем.
(*ct.param)[1].in.a=0x5555;
Почему это компилируется? потому что в си массивы и указатели - братья на век.
PARAMDESC param[256]; - это просто массив. Доступ к значению вы производите так : param[i]. Это равно param[i] == *(param + i * sizeof(PARAMDESC))
PARAMDESC (*param)[256]; - это указатель на массив. Доступ чуток подправляете : (* param)[i].
Разница в том, что PARAMDESC и PARAMDESC [256] имеют разный размер в 256 раз. В неправильном доступе получаете : param[i] == *(param + i * sizeof(PARAMDESC[256]))
По типам подробнее :
PARAMDESC (*param)[256]; - указатель на массив PARAMDESC [256]
* param == param[0] - массив PARAMDESC [256] с индексом ноль
param[i] - другой массив PARAMDESC [256] с индексом i
param[i]->in == param[i][0].in - при команде -> сначала массив param[i] преобразуется в тип * PARAMDESC с индексом ноль.
(* param)[i] == param[0][i] - i - ый элемент у массива с индексом ноль.
(* param)[i].in == param[0][i].in - доступ к полю правильный