2017-10-13 135 views
3

我想做一個霍夫曼代碼來練習C編碼,我一直在創建相同的錯誤。C數組的指針結構realloc()錯誤

讓我來解釋一下代碼。 首先,它生成以下結構:

struct sNo { 
    int valor; 
    char letra; 
    struct sNo *esq; 
    struct sNo *dir; 
}; 
typedef struct sNo sNo; 

然後它創建結構的數組(「否」):

sNo *No; 
No = calloc(qtd_no, sizeof(sNo)); 

它從鍵盤讀取載置在該數組中的字符串的文字和它出現的次數。像下面字「胡言亂語」表示:

No: a/5 b/2 r/2 c/1 d/1 

現在,爲了使霍夫曼樹,它的需要,我創建另一個陣列(「PNO」),並指出了原數組:

int qtd_pno = qtd_no; 
sNo **pNo; 
pNo = calloc(qtd_pno, sizeof(sNo*)); 
for (i = 0; i < qtd_pno; i++){ 
    pNo[i] = &No[i];  
} 

的兩個陣列出現這樣的:

No: a/5 b/2 r/2 c/1 d/1 
pNo: a/5 b/2 r/2 c/1 d/1 

之後,它可以像下面的指針數組進行排序,而不改變原始之一:

No: a/5 b/2 r/2 c/1 d/1 
pNo: c/1 d/1 r/2 b/2 a/5  

但是,當它試圖提高 '否' 數組的大小...

qtd_no++; 
No = realloc(No,(sizeof(sNo) * qtd_no)); 

...這是與數組會發生什麼:

No: a/5 b/2 r/2 c/1 d/1 /0 
pNo: c/1 d/1 r/2 b/2 /0 

什麼像這樣:

No: a/5 b/2 r/2 c/1 d/1 /0 
pNo: c/1 d/1 r/2 b/2 �/1288268632 

請注意,我沒有改變任何'pNo'數組,但不知何故值指出的是。我認爲這可能是動態內存分配的一些特定特性,但我不確定。

編輯
完整的代碼如下:

#include <stdio.h> 
#include <stdlib.h> 
#include <string.h> 


//Definicao do tipo struct No 
struct sNo { 
    int valor; 
    char letra; 
    struct sNo *esq; 
    struct sNo *dir; 
}; 
typedef struct sNo sNo; 


//Funcoes 
void SelectionSort(sNo *A[], int qtd_no); 
void ImprimeArvore (sNo *a); 


int main(){ 
    //Variaveis auxiliares 
    int i, j; 


    //Leitura de texto do teclado 
    char texto[30]; 
    printf("Digite frase \n"); 
    setbuf(stdin, NULL); 
    fgets(texto, 30, stdin); 

    //Criacao dos nos 
    int qtd_no = 0; 
    sNo *No; 

    for(i = 0; i < strlen(texto) && texto[i] != '\0'; i++){ 

     if(texto[i] >= 32){ 

      if(i == 0){ 

       qtd_no++; 
       No = calloc(qtd_no, sizeof(sNo)); 
       if(No == NULL){ 
        printf("Erro: memoria insuficiente\n"); 
        exit(1); 
       } 

       No[i].letra = texto[i]; 
       No[i].valor = 1; 
       No[i].esq = NULL; 
       No[i].dir = NULL; 
       printf("%d\t%c %c\t%d\n", i, texto[i], No[i].letra, No[i].valor); 

      }else{ 

       for(j = 0; j <= qtd_no - 1; j++){ 

        if(texto[i] == No[j].letra){ 
         No[j].valor++; 
         printf("%d %d\t%c %c\t%d\n", i, j, texto[i], No[j].letra, No[j].valor); 
         break; 

        } 

        else if(j == qtd_no - 1){ 

         qtd_no++; 
         No = realloc(No,(sizeof(sNo) * qtd_no)); 
         if(No == NULL){ 
          printf("Erro: memoria insuficiente\n"); 
          exit(1); 
         } 

         No[j+1].letra = texto[i]; 
         No[j+1].valor = 1; 
         No[j+1].esq = NULL; 
         No[j+1].dir = NULL; 
         printf("%d %d\t%c %c\t%d\n", i, j, texto[i], No[j+1].letra, No[j+1].valor); 
         break; 

        } 
       } 
      } 
     } 
    } 

    //Criacao de array com ponteiros para nos 
    int qtd_pno = qtd_no; 

    sNo **pNo; 
    pNo = calloc(qtd_pno, sizeof(sNo*)); 
    if(pNo == NULL){ 
     printf("Erro: memoria insuficiente\n"); 
     exit(1); 
    } 

    for (i = 0; i < qtd_pno; i++){ 
     pNo[i] = &No[i];  
    } 

    //Organizacao dos nos pelo valor 
    SelectionSort(pNo, qtd_pno); 

    //Criacao da arvore binaria 
    while(qtd_pno > 1){ 

     qtd_no++; 

     No = realloc(No,(sizeof(sNo) * qtd_no)); 
     if(No == NULL){ 
      printf("Erro: memoria insuficiente\n"); 
      exit(1); 
     } 

     No[qtd_no - 1].letra = '\0'; 
     No[qtd_no - 1].valor = (pNo[0]->valor) + (pNo[1]->valor); 
     No[qtd_no - 1].esq = pNo[0]; 
     No[qtd_no - 1].dir = pNo[1]; 

     if(qtd_pno > 2){ 
      for(i = 0; i <= qtd_pno-2; i++){ 
       pNo[i] = pNo[i+2]; 
      } 
     } 

     qtd_pno--; 
     pNo = realloc(pNo,(sizeof(sNo*) * qtd_pno)); 
     pNo[qtd_pno - 1] = &No[qtd_no - 1]; 

     if(qtd_pno > 1){ 
      SelectionSort(pNo, qtd_pno); 
     } 
    } 

    sNo *raiz; 
    raiz = pNo[0]; 
    free(pNo); 

    printf("\n%s\n", texto); 

    ImprimeArvore(raiz); 
    printf("\n"); 

} 

//Funcao de organizacao por valor 
void SelectionSort(sNo *A[], int qtd_pno){ 

    sNo *temp; 
    int i, j, Imin; 

    for(i = 0; i < qtd_pno - 1; i++){ 
     Imin = i; 
     for(j = i + 1; j < qtd_pno; j++){ 
      if((A[j]->valor) < (A[Imin]->valor)){ 
       Imin = j; 
      } 
     } 

     temp = A[Imin]; 
     A[Imin] = A[i]; 
     A[i] = temp; 
    } 
} 


void ImprimeArvore(sNo *a){ 

    if(a->letra) printf ("<%c/%d", (a->letra), (a->valor)); 
    else printf ("<_/%d", (a->valor)); 

    if(a->esq != NULL) ImprimeArvore (a->esq); 
    if(a->dir != NULL) ImprimeArvore (a->dir); 

    printf (">"); 

} 
+1

'realloc'只是重新分配更多的內存,但它不會_initialize_新分配的內存。零值或您看到的奇怪值是不確定的值。最好你發佈[mcve]。 –

+2

...還有''realloc()''使傳入的指針值無效,並且同時執行「原始」值的所有其他副本。 – alk

回答

7

與方法的問題是,realloc不會做出有關擴大陣列中發生的任何擔保。

做出哈夫曼樹,它的需要,我創建另一個陣列(「PNO」),並指出了原數組

既然你有其他struct sNo對象中指向calloc -ed陣列,在具有這些結構的塊上調用realloc可能會使這些結構的所有外部指針無效。這就是爲什麼你的代碼在realloc的調用後運行到未定義的行爲。

解決此問題的一種方法是存儲索引而不是指針。只要您保留一個添加新項目的動態數組,但是不會從中刪除項目,這就可以工作。