char A[12]; char *B[12]; int C[12]; double D[12]; double *E[12]; Array tamanho de elemento tam. total end. inicial end. elem i A 1 12 x x+i B 4 48 x x+4i C 4 48 x x+4i D 8 96 x x+8i E 4 48 x x+4i
int a[TAM]
,
podemos encarar a
como um ponteiro constante do tipo int*
int a[10]
, a
equivale a &a[0]
!
(pa + i)
,
onde pa é um ponteiro e i um inteiro,
depende da declaração de pa
tipo *pa
, (pa + i)
equivale a pa + sizeof(tipo)*i
int *pi
e em algum ponto do escopo dessa declaração fizermos
pi+3
, estaremos na realidade somando
3*sizeof(int)
(12
no nosso compilador)
ao valor de pi
!
p1 - p2
fornece o número de elementos
entre p2
e p1
, e não o número de bytes.
int a[5];
int *p = a
,
temos que
p[3] <=> *(p+3) <=> a[3] <=> *(a+3)
tipo nome[tam]
, cálculo do
endereço de memória do elemento a[i]:
a + i
a + sizeof(tipo)*i
int a[3][2]
declara uma array de três
posições onde cada posição é um array de duas posições
char a[2,3]
gera
na memória: a[0,0], a[0,1], a[0,2], a[1,0], ...
tipo nome[tam1][tam2]
, cálculo do
endereço de memória do elemento a[i][j]:
a + tam2*i +j
a + tam2*sizeof(tipo)*i + sizeof(tipo)*j
O layout de structs na memória depende da questão de alinhamento. Cada campo da estrutura que corresponde a uma palavra deve necessariamente começar em um endereço múltiplo de 4. Assim, se tivermos uma declaração como:
struct s{ char c[2]; float b; };
onde um campo ocupando dois bytes precede um campo que corresponde a uma palavra, o compilador terá que deixar dois bytes não utilizados entre o array de caracteres e o float.
struct s s1;memória alocada para s1:
início de s1 ---------------------------------------------------------------------- |s1.c[0]|s1.c[1]| xxxxx | xxxxx | s1.b | s1.b | s1.b | s1.b | ----------------------------------------------------------------------
Os bytes não usados na memória alocada a um struct são chamados de padding.
Observe que o início de cada estrutura tem que ser sempre alinhado, senão não saberemos quantos bytes devem ser "pulados" para chegar a um endereço múltiplo de 4. Isso é especialmente relevante na hora em que montamos um array de structs, já que os elementos de um array são alocados contiguamente na memória.
O tamanho total da struct tem que já ser calculado
para o caso da struct ser usada dentro de um array
e respeitar a regra de cálculo do tamanho total
do array, usando sizeof
(sizeof(array)=num_elem*sizeof(elem)).
Por isso, o padding pode às vezes ocorrer no final.
Por exemplo, a declaração:
struct s { float b; char c[2]; };indica que o campo b deve estar sempre alinhado em um múltiplo de 4 bytes. Como a estrutura pode vir a ser usada em um array, o compilador irá automaticamente colocar um padding de 2 bytes ao final da estrutura, ou seja, o sizeof de s será 8.
Para a declaração:
struct s bobo[2];a alocação de memória ficaria:
-------------------- início de bobo ---> | bobo[0].b | -------------------- | bobo[0].b | -------------------- | bobo[0].b | -------------------- | bobo[0].b | -------------------- | bobo[0].c[0] | -------------------- | bobo[0].c[1] | -------------------- | XXX | -------------------- | XXX | -------------------- | bobo[1].b | -------------------- | bobo[1].b | -------------------- | bobo[1].b | -------------------- | bobo[1].b | -------------------- | bobo[1].c[0] | -------------------- | bobo[1].c[1] | -------------------- | XXX | -------------------- | XXX | --------------------
sizeof
para as
seguintes structs?
struct X { char c; int a,b; } struct X { char c,d; int a,b; }
struct X { char c,d; int a; char e; }
referência: C Programming Notes. Steve Summit.