2014-11-21 52 views
0

所以我是C編程的新手,並且在使用下面的代碼創建鏈表時遇到了問題。我一直存在的問題是,fscanf每次讀取某些內容時都會更改這些變量。所以我的頭指針值不斷變化。有沒有辦法來解決這個問題?謝謝!讀入文件並在c中創建一個雙向鏈表c

經過一番討論後,我意識到這是因爲結構中的助記符是一個指針,所以頭的助記符將會改變,因爲它只是指向指針。有沒有辦法解決這個問題而不改變結構本身? (意味着留下結構INSTR助記符爲指針)

void linkTypeInstr(struct InstrType *it, char *c, FILE *mfp){ 
    int count = 0; 
    char type[2], mnemonic[11]; 
    uint32_t uid = 0, pretty = 0; 
    struct Instr *head = NULL; 
    struct Instr *ptr = NULL; 
    /*read through the file in format*/ 
    while(fscanf(mfp, "%s %u %s %u ", type, &uid, mnemonic, &pretty) != NULL){ 
     if(head != NULL) 
      printf("head: %s\n", head -> mnemonic); 
     /*check if is the match type*/ 
     if(*type == *c){ 
      /*make a new struct instr for the item want to add*/ 
      struct Instr *temp = malloc(sizeof(struct Instr)); 
      memset(temp, 0, sizeof(struct Instr)); 
      temp -> uid = uid; 
      temp -> pretty = pretty; 
      temp -> mnemonic = mnemonic; 
      temp -> next = NULL; 
      temp -> prev = NULL; 
      printf("temp: %s\n", temp -> mnemonic); 
      printf("count: %d\n", count); 
      /*check if list is empty, set ptr to head*/ 
      if(count == 0){ 
       head = temp; 
       count++; 
      } 
      /*if list is not empty, find the place to put the item in alphabetical order*/ 
      else{ 
       ptr = head; 
       printf("head: %s\n", head -> mnemonic); 
       while(ptr != NULL){ 
        /*if temp should come after ptr in the order*/ 
        if(strcmp(ptr -> mnemonic, temp -> mnemonic) < 0){ 
         if(ptr -> next == NULL){ 
          ptr -> next = temp; 
          temp -> prev = ptr; 
          count++; 
          ptr = NULL; 
         } 
         else if(strcmp(temp -> mnemonic, ptr -> next -> mnemonic) < 0){ 
          temp -> next = ptr -> next; 
          ptr -> next -> prev = temp; 
          ptr -> next = temp; 
          temp -> prev = ptr; 
          count++; 
          ptr = NULL; 
         } 
         else 
          /*if should be after ptr -> next*/ 
          ptr = ptr -> next; 
        } 
        /*if temp should come before ptr in the order*/ 
        else if(strcmp(temp -> mnemonic, ptr -> mnemonic) < 0){ 
         if(ptr -> prev == NULL){ 
          ptr -> prev = temp; 
          temp -> next = ptr; 
          head = temp; 
          count++; 
          ptr = NULL; 
         } 
         else if(strcmp(ptr -> prev -> mnemonic, temp -> mnemonic) < 0){ 
          ptr -> prev -> next = temp; 
          temp -> prev = ptr -> prev; 
          ptr -> prev = temp; 
          temp -> next = ptr; 
          count++; 
          ptr = NULL; 
         } 
         else 
          /*if should be before ptr -> prev*/ 
          ptr = ptr -> prev; 
        } 
       } 
      } 
     } 
    } 
    it -> count = count; 
    it -> head = head; 
} 


struct Instr { 
     uint32_t uid; /* Unique identification bits */ 
     uint32_t pretty; /* The type of pretty print format this Instr is */ 
     char *mnemonic; /* The human readable mnemonic */ 
     struct Instr *next; /* Pointer for doubly linked list */ 
     struct Instr *prev; /* Pointer for doubly linked list */ 
}; 

struct InstrType { 
     char type; /* Should be R, I, or J */ 
     size_t count; /* Length of Instr list */ 
     struct InstrType *next; /* Points to the next InstrType node */ 
     struct InstrType *prev; /* Points to the next InstrType node */ 
     struct Instr *head; /* Points to the first Instr node of this type */ 
}; 

文件我嘗試讀取這個樣子:

r 00000020 add 3 
r 00000021 addu 3 
r 00000022 sub 3 
r 00000023 subu 3 
r 00000018 mult 2 
r 00000019 multu 2 
r 0000001a div 1 
r 0000001b divu 1 
r 00000010 mfhi 0 
r 00000011 mthi 0 
r 00000012 mflo 0 
r 00000013 mtlo 0 
r 00000000 sll 8 
r 00000002 srl 8 
r 00000003 sra 8 
r 00000004 sllv 3 
r 00000006 srlv 3 
r 00000007 srav 3 
r 00000024 and 3 
r 00000025 or 3 
r 00000026 xor 3 
r 00000027 nor 3 
r 0000002a slt 3 
r 0000002b sltu 3 
r 00000008 jr 0 
r 00000009 jalr 2 
r 0000000c syscall 5 
i 20000000 addi 2 
i 24000000 addiu 2 
i 3c000000 lui 2 
i 28000000 slti 2 
i 2c000000 sltiu 2 
i 30000000 andi 2 
i 34000000 ori 2 
i 38000000 xori 2 
i 80000000 lb 4 
i 84000000 lh 4 
i 88000000 lwl 4 
i 8c000000 lw 4 
i 90000000 lbu 4 
i 98000000 lwr 4 
i a0000000 sb 4 
i a4000000 sh 4 
i a8000000 swl 4 

,結果當我運行這個最終總是改變我頭PTR到新的臨時創建的:

temp: add 
count: 0 
head: addu 
temp: addu 
count: 1 
head: addu 
... 

代碼調用函數如下:

int main(int argc, char *argv[]){ 
    int c; 
    int iFlag = 0, oFlag = 0; 
    char mFileName[256] = "instruction_mapping.txt"; 
    char oFileName[256]; 
    char iFileName[256]; 
    extern char *optarg; 
    FILE *mfp, *ifp, *ofp; 

    /*create three struct instrtype nodes*/ 
    struct InstrType *itR = malloc(sizeof(struct InstrType)); 
    struct InstrType *itI = malloc(sizeof(struct InstrType)); 
    struct InstrType *itJ = malloc(sizeof(struct InstrType)); 

    memset(itR, 0, sizeof(struct InstrType)); 
    memset(itI, 0, sizeof(struct InstrType)); 
    memset(itJ, 0, sizeof(struct InstrType)); 

    /*link the struct instrtype together*/ 
    if(itR != NULL && itI != NULL && itJ != NULL){ 
     itR -> prev = NULL; 
     itR -> next = itI; 
     itI -> prev = itR; 
     itI -> next = itJ; 
     itJ -> prev = itI; 
     itJ -> next = NULL; 
    } 

    /*set up instrtypes*/ 
    itR -> type = 'R'; 
    itI -> type = 'I'; 
    itJ -> type = 'J'; 

    /* parse arguments */ 
    while ((c = getopt(argc, argv, "m:i:o:h")) != -1){ 
     switch(c){ 
      case 'h': 
       USAGE(argv[0]); 
       return EXIT_SUCCESS; 
      case 'm': 
       strcpy(mFileName, optarg); 
       break; 
      case 'i': 
       iFlag = 1; 
       strcpy(iFileName, optarg); 
       break; 
      case 'o': 
       oFlag = 1; 
       strcpy(oFileName, optarg); 
       break; 
      default: 
       USAGE(argv[0]); 
       return EXIT_FAILURE; 
     } 
    } 

    /*check -i and -o must be in argv*/ 
    if(iFlag == 1 && oFlag == 1){ 
     mfp = fopen(mFileName, "r"); 
     if(mfp == NULL){ 
      printf("Cannot open instruction mapping file\n"); 
      EXIT_FAILURE; 
     } 
     printf("mapping file: %s\n", mFileName); 
     ifp = fopen(iFileName, "r"); 
     if(ifp == NULL){ 
      printf("Cannot open input file\n"); 
      EXIT_FAILURE; 
     } 
     printf("input file: %s\n", iFileName); 
     ofp = fopen(oFileName, "w"); 
     if(ofp == NULL){ 
      printf("Error creating or writing file\n"); 
      EXIT_FAILURE; 
     } 
     printf("output file: %s\n", oFileName); 

     /* make linked lists of instr in R, I, J instrtype */ 
     linkTypeInstr(itR, "r", mfp); 
     linkTypeInstr(itI, "i", mfp); 
     linkTypeInstr(itJ, "j", mfp); 


     if(mfp != NULL) 
      fclose(mfp); 
     if(ifp != NULL) 
      fclose(ifp); 
     if(ofp != NULL) 
      fclose(ofp); 
    } 
    else{ 
     printf("Must have both input and output files\n"); 
     return EXIT_FAILURE; 
    } 
    free(itR); 
    free(itI); 
    free(itJ); 
    return EXIT_SUCCESS; 
} 
+3

我可以建議試圖將其分解成更小的部分並分別進行測試?嘗試將列表操作封裝在操作列表結構的函數中。儘管這是C而不是C++,但它會爲建立抽象和隔離這些抽象操作提供回報。 – sfjac 2014-11-21 21:45:20

+0

發佈展現此行爲的最小輸入文件。順便說一句:'char type [1]'這裏是一個問題。在這個長度爲1的緩衝區中,可以存儲最大長度爲... 0的字符串。嘗試'char type [20]'。也助記符可以包含字符串的最大長度只有4. – 2014-11-21 21:46:23

+0

我的字符的大小對我來說工作得很好,因爲即時閱讀文件將以我剛剛發佈的格式進行確認。 – zombiecircus 2014-11-21 21:52:19

回答

0

你的問題是這樣的線:

temp -> mnemonic = mnemonic;

該TEMP->助記符是一個指針的事實意味着它將ALLWAYS指向助記符陣列的相同字符11。由於頭部是從temp分配的,所以head->助記符將指向相同的11個字符,這些字符將在下次調用fscanf時被覆蓋。

的解決辦法是改變你的

struct Instr { uint32_t uid; /* Unique identification bits */ uint32_t pretty; /* The type of pretty print format this Instr is */ char *mnemonic; /* The human readable mnemonic */ struct Instr *next; /* Pointer for doubly linked list */ struct Instr *prev; /* Pointer for doubly linked list */ };

struct Instr { uint32_t uid; /* Unique identification bits */ uint32_t pretty; /* The type of pretty print format this Instr is */ char mnemonic[11]; /* The human readable mnemonic */ struct Instr *next; /* Pointer for doubly linked list */ struct Instr *prev; /* Pointer for doubly linked list */ };

,而是用strncpy()函數爲它分配:

strncpy(temp -> mnemonic, mnemonic, 11);

+0

順便說一下,你也應該知道fscanf不返回一個指針,而是返回成功匹配項的數量。 while循環應檢查它是否返回4而不是NULL。一個好的編譯器會通過一條警告消息來警告你:warning:指針和整數之間的比較 – 2014-11-21 22:32:21

+0

有沒有辦法在不改變結構本身的情況下修復它? – zombiecircus 2014-11-21 22:38:39

+0

@zombiecircus使用'strdup'複製字符串(或更便攜的'malloc'和'strcpy')。兩者都要求你在完成內存之後調用'free',這意味着在你的'destroy_item'函數中,或者你用來釋放一個項目所用的內存的任何函數,你必須用助記符作爲參數來調用'free'在釋放它所屬的項目之前。 – 2014-11-22 01:04:42