2017-10-13 39 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的调用后运行到未定义的行为。

解决此问题的一种方法是存储索引而不是指针。只要您保留一个添加新项目的动态数组,但是不会从中删除项目,这就可以工作。