Comment Les Tableaux C Sont-Ils Représentés En Mémoire?

Je crois comprendre comment les variables et les pointeurs normaux sont représentés en mémoire si vous utilisez C.

Par exemple, il est facile de comprendre qu'un pointeur Ptr aura une adresse, et sa valeur sera une adresse différente, qui est l'espace en mémoire vers lequel il pointe. Le code suivant:

int main(){
    int x = 10;
    int *Ptr;
    Ptr = &x;
return 0;
}

Aurait la représentation suivante en mémoire:

+---------------------+-------------+---------+
| Variable Name       | Address     | Value   | 
+---------------------+-------------+---------+
| x                   | 3342        | 10      |
+---------------------+-------------+---------+
| Ptr                 | 5466        | 3342    |
+---------------------+-------------+---------+

Cependant, je trouve difficile de comprendre comment les tableaux sont représentés en mémoire. Par exemple, le code:

int main(){
    int x[5];
        x[0]=12;
        x[1]=13;
        x[2]=14;

    printf("%pn",(void*)x);
    printf("%pn",(void*)&x);

return 0;
}

Affiche la même adresse deux fois (par souci de simplicité 10568). Ce qui signifie que x== & X. pourtant *x (ou x[0] en notation de tableau) est égal à 12, *(x+1) (ou x[1] en notation de tableau) est égal à 13 et ainsi de suite. Comment cela peut-il être représenté? Une façon pourrait être ceci:

+---------------------+-------------+----------+----------------------+
| Variable Name       | Address     | Value    | Value IF array       |
+---------------------+-------------+----------+----------------------+
| x                   | 10568       | 10568    | 12                   |
+---------------------+-------------+----------+----------------------+
|                     | 10572       |          | 13                   | 
+---------------------+-------------+----------+----------------------+
|                     | 10576       |          | 14                   | 
+---------------------+-------------+----------+----------------------+
|                     | 10580       |          | trash                | 
+---------------------+-------------+----------+----------------------+
|                     | 10584       |          | trash                | 
+---------------------+-------------+----------+----------------------+

Est proche de ce qui se passe, ou complètement éteint?

25
demandé sur Mankarse 2011-10-21 05:19:59

8 réponses

Un tableau est un bloc d'objets contigus sans espaces entre les deux. Cela signifie que x dans votre deuxième exemple est représenté en mémoire comme:

+---------------------+-------------+---------+
| Variable Name       | Address     | Value   | 
+---------------------+-------------+---------+
| x                   | 10568       | 12      |
|                     |             +---------+
|                     |             | 13      |
|                     |             +---------+
|                     |             | 14      |
|                     |             +---------+
|                     |             | ??      |
|                     |             +---------+
|                     |             | ??      |
+---------------------+-------------+---------+

C'est-à-dire, x est cinq intgrand, et a une seule adresse.

La partie étrange des tableaux n'est pas dans la façon dont ils sont stockés - c'est la façon dont ils sont évalués dans les expressions. Si vous utilisez un nom de tableau quelque part qu'il n'est pas l'objet des opérateurs unaires & ou sizeof, il évalue à l'adresse de son premier membre.

Autrement dit, si vous écrivez simplement x, vous obtiendrez une valeur 10568 avec le type int *.

Si, d'autre part, vous écrivez &x, alors la règle spéciale ne s'applique pas - donc l'opérateur & fonctionne comme il le fait normalement, ce qui signifie qu'il récupère l'adresse du tableau. Dans l'exemple, ce sera une valeur 10568 avec le type int (*)[5].

La raison que x == &x, c'est que l'adresse du premier élément d'un tableau est nécessairement égale à l'adresse de la table lui-même, puisqu'un tableau commence par son premier membre.

32
répondu caf 2011-10-21 02:33:06

Votre diagramme est correct. L'étrangeté autour de &x n'a rien à voir avec la façon dont les tableaux sont représentés en mémoire. Cela a à voir avec array-> pointer decay. {[1] } par lui - même dans le contexte de la valeur se désintègre en un pointeur vers son premier élément; c'est-à-dire qu'il est équivalent à &x[0]. &x est un pointeur sur un tableau, et le fait que les deux sont numériquement égal est juste de dire que l'adresse d'un tableau est numériquement égale à l'adresse de son premier élément.

22
répondu Raymond Chen 2011-10-21 01:27:36

Oui, vous l'avez. Un tableau C trouve la valeur indexée x[y] en calculant x + (y * sizeof(type)). {[2] } est l'adresse de départ du tableau. {[3] } est un décalage de cela. x[0] produit la même adresse que X.

Les tableaux multidimensionnels sont similaires, donc int x[y][z] va consommer sizeof(int) * y * z mémoire.

Pour cette raison, vous pouvez faire quelques trucs stupides de pointeur C. Cela signifie également obtenir la taille d'un tableau est (presque) impossible.

2
répondu Schwern 2011-10-21 01:32:34

Un tableau en C est un bloc séquentiel de mémoire avec le bloc de chaque membre de la même taille. C'est pourquoi les pointeurs fonctionnent, vous cherchez un décalage basé sur l'adresse du premier membre.

0
répondu alex 2011-10-21 01:28:49

La section Tableaux et pointeurs de la FAQ C contient des informations utiles.

0
répondu Sinan Ünür 2011-10-21 01:33:11

Un tableau C est juste un bloc de mémoire qui a des valeurs séquentielles de la même taille. Lorsque vous appelez malloc (), il vous accorde simplement un bloc de mémoire. foo[5] est le même que *(foo + 5).

Exemple-foo.c:

#include <stdio.h>

int main(void)
{
    int foo[5];
    printf("&foo[0]: %tx\n", &foo[0]);
    printf("foo: %tx\n\n", foo);
    printf("&foo[3]: %tx\n", &foo[3]);
    printf("foo: %tx\n", foo + 3);
}

Sortie:

$ ./foo
&foo[0]: 5fbff5a4
foo: 5fbff5a4

&foo[3]: 5fbff5b0
foo: 5fbff5b0
0
répondu ObscureRobot 2011-10-21 02:09:16

Daniel,

Ce n'est pas difficile. Vous avez l'idée de base et il n'y a pas beaucoup de différence dans la représentation de la mémoire des tableaux. si vous déclarez un tableau, dites

     void main(){
         int arr[5]={0,1,2,3,4};


     }

Vous avez initialisé (défini) le tableau. Ainsi, les cinq éléments seront stockés dans cinq endroits adjacents en mémoire. vous pouvez l'observer en référençant l'adresse mémoire de chaque élément. Pas comme les autres types de données primitives en C, un identifiant de tableau (ici, arr) représente lui-même son pointeur. Idée semble vague, si vous êtes un débutant, mais vous vous sentirez à l'aise que vous allez sur.

      printf("%d",arr);

Cette ligne vous montrera l'adresse mémoire du premier élément, arr[0]. Ceci est similaire au référencement de l'adresse du premier élément.

      printf("%d",&arr[0]);

Maintenant, vous pouvez afficher les emplacements de mémoire de tous les éléments. Le morceau de code suivant fera le travail.

    int i;
    for(i=0;i<5;i++){
       printf("location of %d is %d\n",arr[i],&arr[i]);
    } 

Vous verrez chaque adresse par incréments de quatre.(si vos entiers ont une longueur de 32 bits). Donc, vous pouvez facilement comprendre comment l' les tableaux sont stockés dans la mémoire.

Vous pouvez également essayer la même chose en utilisant une méthode différente.

    int i;
    for(i=0;i<5;i++){
       printf("location of %d is %d\n",*(a+i),a+i);
    }

Vous obtiendrez le même ensemble de réponses dans les deux cas et essaierez d'obtenir l'équivalence.

Essayez la même expérience en utilisant différents types de données(char, float et struct). Vous verrez comment les écarts entre les éléments adjacents varient en fonction de la taille d'un seul élément.

0
répondu Tharindu Rusira 2011-10-24 18:14:21

Int x[] produit le même résultat que int* x;

C'est juste un pointeur

Par conséquent, les notations x [i] et *(x + i) produisent le même résultat.

-1
répondu Anonrandom 2011-10-21 01:29:53