2009-12-11 7 views
0

EDIT: Au départ, je l'avais transcrit i++ pas i--uint comme indices

Le code est maintenant comme il était, et le code dans les blocs compilable de code et des œuvres.


Pourquoi, si unsigned int i; est utilisé à la place de int i; dans l'extrait de code ci-dessous, en utilisant le résultat ne fonction dans un segfault?

void insertion_sort_int_array(int * const Ints, unsigned int const len) { 
    unsigned int pos; 
    int key; 
    int i; 

    for (pos = 1; pos < len; ++pos) { 
     key = Ints[pos]; 
     for (i = (pos - 1); (i >= 0) && Ints[i] > key; i--) { 
      Ints[i + 1] = Ints[i]; 
     } 
     Ints[i + 1] = key; 
    } 
} 
+1

Quel est le but de (i> = 0) si i est non signé? –

+0

Quel est le but de (i> = 0) indépendamment? C'est toujours vrai. –

Répondre

2
insertionSort(array A) 
begin 
    for x := 1 to length[A]-1 do 
    begin 
     value := A[x]; 
     i := x - 1; 
     while i >= 0 and A[i] > value do 
     begin 
      A[i + 1] := A[i]; 
      i := i - 1; 
     end; 
     A[i + 1] := value; 
    end; 
end; 

La seule différence entre l'algorithme de tri d'insertion standard et votre code est que vous incrémenter i au lieu de décrémentation. C'est ton problème. Je parie que dans le code que vous êtes en train de compiler et de lancer, vous avez i-- au lieu de i ++ dans la boucle interne. C'est pourquoi les non signés font une différence - ils ne peuvent pas être négatifs, donc la boucle interne ne finira jamais. Avez-vous copié le code incorrect lors de votre publication?

EDIT:

Eh bien, maintenant que vous avez modifié le code affiché, tout cela est logique, non? Un non signé va simplement déborder à INT_MAX lorsque vous le décrémentez au-delà de 0, ce qui vous amènera à accéder à la mémoire en dehors des limites du tableau.

+0

Notez que (dans l'esprit de l'OP) ce code va planter si vous utilisez un * unsigned * int pour i. Quand i atteint 0, il mettra i: = i-1 qui est -1 dans un int signé, mais un * très grand nombre positif * dans un int non signé, de sorte que la boucle ne sortira jamais (autre que de s'écraser en essayant de accéder à la mémoire en dehors des limites du tableau). –

+0

Ceci était la pièce réelle du code psuedocode utilisé pour générer le code utilisé dans la publication. –

1

Qu'est-ce qui maintient i + 1 dans les limites de votre tableau 'ints'? Il semblerait que des données mal formées dans votre tableau vous amèneront à indexer des zones de mémoire auxquelles vous ne devriez pas avoir accès.

+0

@_ande_turner, mais 'key' dans 'ints [i]> key' est lu dans votre tableau initial. Il semble un peu dangereux – Trent

2

Le code affiché échouera dans les deux cas (avec éventuellement une faute de seg- ment, éventuellement une corruption de mémoire).

La boucle interne à partir de pos-1 et scans vers le haut en mémoire jusqu'à ce qu'une condition aléatoire est remplie - il ne vérifie pas si elle a dépassé l'extrémité de la matrice, de sorte que se déroulera gaiement jusqu'à ce qu'il se bloque ou la La condition de fin arrive à être satisfaite par le contenu (indéfini) de la mémoire qu'il corrompt.

Vous avez probablement voulu numériser vers le bas en mémoire (en utilisant i-- dans la boucle), auquel cas il échouerait parce que la boucle atteindra 0. Soustraire 1 de 0 vous donne un très grand nombre positif dans un non signé, donc la boucle ne se terminera jamais (i> = 0 est toujours vrai) et il accédera à de la mémoire quelque part dans la région de Pluton.

+0

Si à la première itération de la boucle, ints [i] est inférieur ou égal à la clé, alors il quittera la boucle sans rien faire. Cependant, si ints [i] est plus grand que key, alors il le copiera dans ints [i + 1], puis ira i + 1 pour l'itération suivante, donc il remplira juste la mémoire suivant ints [i] avec la valeur de la première itération de la boucle jusqu'à ce qu'elle écrase quelque chose d'important (par exemple, sur certains ordinateurs, elle pourrait tomber dans un cadre de pile ou une adresse d'E/S, provoquant un crash) ou (plus probablement) (provoquant un accident). –

+0

Il s'agit d'un plantage en attente, que vous utilisiez int ou unsigned-int. –

+0

Sa valeur de départ est i = pos-1. Au fur et à mesure que nous progressons dans la boucle, i est incrémenté à chaque fois (donc ce sera pos, alors pos + 1, puis pos + 2 ...). La boucle se termine lorsque "(i> = 0) && Ints [i]> touche". C'est-à-dire que la boucle continuera jusqu'à ce que je devienne négatif, ou jusqu'à ce que l'entrée ith dans votre tableau soit plus grande que la clé. Puisque pos n'est pas mentionné dans la condition finale pour la boucle, pos n'a aucune influence sur le moment où la boucle se terminera (autre que la fourniture de la valeur de départ pour i). Il semble que vous ayez besoin de lire un peu plus sur le fonctionnement des boucles for-loops. –

0

i [provoquera] un accès au-delà des limites du tableau.

Importation limites et la comparaison à UINT_MAX au lieu des (i >= 0) précédentes résout le problème:

#include <limits.h> 

void insertion_sort_int_array(int * const Integers, unsigned int const N) 
{ 
    unsigned int o; 
    int target; 
    unsigned int i; 

    for (o = 1; o < N; o++) { 
     target = Integers[o]; 
     for (i = (o - 1); (i != UINT_MAX) && (Ints[i] > target); i--) { 
      Integers[i + 1] = Integers[i]; 
     } 
     Integers[i + 1] = key; 
    } 
} 
0

Pourquoi, si non signé int i; est utilisé au lieu de int i; dans l'extrait de code ci-dessous, utilise-t-il le résultat de la fonction dans une erreur de segmentation?

Parce que pour unsigned int i, i >= 0 est toujours vrai, de sorte que votre boucle est peu probable de mettre fin quand vous voulez.

Vous devez toujours être extrêmement prudent lorsque vous faites une boucle vers l'arrière (de haut en bas) si votre compteur n'est pas signé.