2015-08-13 7 views
6

ho definito di matrice nei seguenti formati, ma a quanto pare il programma funziona bene solo in caso B.ambiguità nella dichiarazione di matrice 2D in C

CASO A:

int **M1; 
M1 = (int **)malloc(m * sizeof(int *)); 
for (int i=0; i<m; i++){ 
    M1[i] = (int *)malloc(d * sizeof(int)); 
} 

CASO B:

int (*M1)[m] = malloc(sizeof(int[m][d])); 

Mi viene visualizzato un errore di segmentazione in CASE A. Quale potrebbe essere la causa?

+2

Il codice A funziona perfettamente per me. Qual è il tuo ambiente? – blue112

+1

Dove si ottiene esattamente l'errore di segmentazione? –

+0

[Si prega di non trasmettere il risultato di 'malloc()'] (http://stackoverflow.com/a/605858/3233393). – Quentin

risposta

3

Il codice seguente compila senza errori o avvisi in gcc compilatore,

int **M1,i; 
    M1 = (int **)malloc(5 * sizeof(int *)); 
    for (i=0;i<5;i++){ 
     M1[i] = (int *)malloc(2 * sizeof(int)); 
    } 
    M1[0][0]=111; 
    M1[0][1]=222; 
    printf("\n%d %d",M1[0][0],M1[0][1]); 

esprime 111 222 come uscita.

Il problema potrebbe trovarsi in un altro punto del codice.

1

CASO A;

M1 è un puntatore a un puntatore. Si sta allocando memoria per un array 2D di tipo int ed è possibile memorizzare i valori m*d nella matrice.

M1[0][0] a M[m-1][d-1] sono un accesso valido per questo array al fine di ottenere il valore di tipo int e qualsiasi altra cosa comporta un comportamento non definito.

Caso B:

M1 è un puntatore a una matrice di tipo int che ha m elementi.

nel caso A, la colpa di segmentazione più probabile sembra a causa della serie di accesso legato

+0

No, assegna la memoria per il numero 'm' di' int * ', che è perfettamente a posto. È anche perfettamente in grado di accedere a 'M1 [0]', si ottiene semplicemente un 'int *', non un 'int'. – Jite

+0

@Jite Penso che tu abbia frainteso la mia risposta. Sì, int * 'va bene, ma intendevo che i valori validi validi accessibili sono' M1 [0] [0] 'a' M1 [4] [4] ' – Gopi

+1

Da dove prendi' [4] [4] '? Non conosciamo il valore di 'm' né di' d'? – Jite

1

Un puntatore e una serie sono cose diverse. Un puntatore a un tipo contiene l'indirizzo in cui è allocata una variabile di tipo dichiarato.

Un array di un tipo è uno spazio di memoria in cui le variabili del tipo dichiarato sono memorizzate in modo contiguo.

Ora sei una dichiarazione. Non c'è alcuna ambiguità (anche se non è così evidente) nelle dichiarazioni C. In caso Un voi hanno dichiarato:

int **M1; 

Questo non è un array 2D, nemmeno uno monodimensionale. Stai dichiarando una variabile, M!, come puntatore a un altro puntatore a un int. Nella parola piano M1 verrà trattenuto l'indirizzo di un'altra variabile che a sua volta contiene l'indirizzo di cui nella memoria è memorizzato un numero intero. Now executing:

M1 = (int **)malloc(m * sizeof(int *)); 

assegnato al M1 l'indirizzo un'area di memoria che può memorizzare fino a m contigui puntatori interi, un accesso alla memoria puntata da M1, e successive riprese agisce come accesso matrice (ma non lo è).Questo è più o meno equivalente alla dichiarazione statico:

int *[m]; //an array of pointers to int 

Poi assegnando ogni elemento di questo pseudo-array di memoria per d interi contigui:

for (int i=0; i<m; i++) 
{ 
    M1[i] = (int *)malloc(d * sizeof(int)); 
} 

ora hanno spazio per memorizzare d consecutivo numeri interi che iniziano agli indirizzi salvati in M1[i] per i = 0-> d-1.

Cosa succede quando si tenta di accedere a un valore utilizzando gli indici: M1[a][b]? Il compilatore recupera l'indirizzo indicato da M1 e utilizza il primo indice (a), recupera il contenuto indicato dall'indirizzo nella posizione atht dell'array di puntatori. Questo punta al primo intero del sottospazio che abbiamo assegnato per contenere d int consecutive. Questo è davvero un array monodimensionale di int. Applicando il secondo pedice ad esso il compilatore recupera finalmente il numero intero richiesto. Cose a un array bidimensionale che si rivolge, ma senza banana! Non è una matrice bidimensionale di int. :-)

In caso B si dichiara un puntatore a un array monodimensionale di int, a cui si stanno assegnando spazio sufficiente per contenere l'array bidimensionale. Perché in C non esiste il concetto di matrice multidimensionale, tuttavia il principio di base della serie di array di matrice .... ecc (ad libitum), la dichiarazione:

int (*M1)[m] = malloc(sizeof(int[m][d])); 

come un puntatore a modimensiional array con spazio allocato per un array di elementi [m][d] ha fatto il trucco.

Ma ovviamente entrambe le soluzioni sono sbagliate!

Si stanno utilizzando gli effetti collaterali per ottenere ciò che si desidera, ma utilizzando i surrogati di ciò che si è dichiarato necessario: una matrice bidimensionale di int.

La soluzione corretta è quella di definire un puntatore a una matrice bidimensionale di interi in cui è richiesto solo il primo pedice:

int (*M1)[][m]; //declare a pointer to a real array 

M1 = malloc(m * d * sizeof(int)); //Allocate room for bidimensional array 

for (int i=0; i<m; i++) 
    for (int j=0; j<d; j++) 
    { 
     (*M1)[i][j] = (i*100)+j; //Fill elements with something using bidimensional subscripting 
    } 
for (int i=0; i<m; i++) 
    for (int j=0; j<d; j++) 
    { 
     printf("[%d][%d]=%d\n", i, j, (*M1)[i][j]); //Check back data... 
    } 

Ora uno sguardo a quello che succede se si va fuori dai limiti nel 3 casi. In caso Un se si ottiene fuori limite con il primo indice potrai raccogliere un puntatore sbagliato che causerà immediatamente colpa di una memoria, nel caso in cui B si avrà colpa di memoria solo se si va fuori di processo memoria indirizzabile, uguale per la soluzione corretta. Questo dovrebbe rispondere alla tua domanda.

scorso, perché stiamo parlando di circa misunderstandigs vettori e puntatori, non fraintendere alla norma ISO 9899: 2011§6.7.6.3/7 che dice:

Una dichiarazione di un parametro come '' l'array di tipo '' deve essere regolato su '' puntatore qualificato per digitare '', dove i qualificatori di tipo (se presenti) sono quelli specificati all'interno di [e] della derivazione del tipo di matrice.Se la parola chiave static appare anche all'interno [e] della derivazione del tipo array , quindi per ogni chiamata alla funzione, il valore dell'argomento effettivo corrispondente di deve fornire l'accesso al primo elemento di un array con almeno molti elementi specificati dall'espressione di dimensione .

che prevede soltanto che array saranno trasmessi soltanto con riferimento (regolata automaticamente dal compilatore), non per valore (cioè legale per le strutture esempio). Non ti viene richiesto di fornire alcun puntatore qualificato invece di un array nella chiamata di funzione o il programma si blocca (Una dichiarazione di un parametro come '' array di tipo '' deve essere regolata su '' puntatore qualificato per digitare '' - significa che verrà regolato dal compilatore, non da te). I casi come char *[] e char ** funzionano per il motivo sopra riportato, non perché sia ​​legale scambiarli!