J'utilise malloc pour créer un tableau en C. Mais j'ai eu l'erreur de segmentation lorsque j'ai essayé d'assigner des valeurs aléatoires au tableau en 2 boucles.
Il n'y a pas d'erreur de segmentation lorsque j'attribue des valeurs à ce tableau en 1 boucle. La taille du tableau est grande. Veuillez consulter le code que j'ai joint. N'importe qui peut me donner une idée de ce qui se passe ici. Je suis assez nouveau à C. Merci beaucoup à l'avance.
int n=50000; float *x = malloc(n*n*sizeof(float)); // there is segmentation fault: int i, j; for (i=0; i<n; i++){ for (j=0; j<n; j++){ x[i*n+j] = random() / (float)RAND_MAX; } } // there is no segmentation fault: int ii; for (ii=0; ii<n*n; ii++){ x[ii] = random() / (float)RAND_MAX; }
3 Réponses :
int
débordement.
50000 * 50000
-> 2,500,000,000 -> plus de INT_MAX
-> comportement non défini (UB ).
Tout d'abord, assurons-nous qu'un calcul de la taille de cette allocation est possible
// float *x = malloc(n*n*sizeof(float)); // Uses at least `size_t` math by leading the multiplication with that type. float *x = malloc(sizeof(float) * n*n); // or better float *x = malloc(sizeof *x * n*n); for (i=0; i<n; i++){ for (j=0; j<n; j++){ x[(size_t)n*i + j] = random() / (float)RAND_MAX; } }
Puis avec une largeur suffisamment vérifiée size_t , utilisez
size_t
math pour faire la multiplication et utilisez size_t
math pour le calcul d'index de tableau. Plutôt que int * int * size_t
, faites size_t*int*int
.
assert(SIZE__MAX/n/n/sizeof(float) >= 1);
2ème boucle pas "échouer" car n * n
n'est pas la grande valeur attendue, mais probablement la même valeur UB dans l'allocation.
Merci! J'ai beaucoup appris. Le problème est résolu lorsque j'utilise size_t pour le calcul d'index x [(size_t) n * i + j]. Je finis par définir n comme size_t au début.
Tout d'abord, vous invoquez un comportement indéfini en raison d'un dépassement d'entier signé. En supposant qu'un int
est de 32 bits, la valeur de 50000 * 50000 dépasse la plage d'un int
, provoquant le débordement.
Vous pouvez résoudre ce problème en mettant sizeof (float) en premier dans l'expression. Le résultat de sizeof
est un size_t
qui est non signé et au moins aussi grand qu'un int
. Ensuite, lorsque chaque n
est multiplié, il est d'abord converti en size_t
évitant ainsi le débordement.
float *x = malloc(sizeof(float)*n*n);
Cependant, même si vous corrigez cela, vous demandez trop de mémoire.
En supposant que sizeof (float)
est de 4 octets, n * n * sizeof (float)
représente environ 10 Go de mémoire. Si vous vérifiez la valeur de retour de malloc
, vous verrez probablement qu'elle renvoie NULL.
Vous devrez rendre votre tableau beaucoup plus petit. Essayez plutôt n = 1000
, qui n'utilisera qu'environ 4 Mo.
Je pense que le problème est lié au dépassement d'entiers:
50 000 x 50 000 = 2,5 milliards
2 ^ 31 ~ 2,1 milliards
Ainsi, vous invoquez un comportement non défini lors du calcul de l'index du tableau. Quant à savoir pourquoi cela fonctionne pour l'un mais pas pour l'autre, c'est juste comme ça. Un comportement non défini signifie que le compilateur (et l'ordinateur) peut faire tout ce qu'il veut, y compris faire ce que vous attendez et planter le programme.
Pour corriger, changez les types de i, j, n et ii en long long à partir de int. Cela devrait résoudre le problème de débordement et l'erreur de segmentation.
Modifier:
Vous devez également vérifier que malloc renvoie un pointeur valide avant d'effectuer des opérations sur le pointeur. Si malloc échoue, vous recevrez un pointeur nul.