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.