2015-02-24 56 views
1

所以我一直在努力學習C一段時間,終於碰到了一堵磚牆。我在網上發現了不同的練習題,而且我真的遇到了這個問題。傳遞給函數後,C指針沒有被設置

起初,我寫了這個代碼的所有主要功能內,它工作得很好,並給出所需的輸出(這裏是工作的例子)

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

typedef struct Student STUDENT; 
typedef struct Teacher TEACHER; 
typedef struct Course COURSE; 

int addStudentToTree(STUDENT *students, STUDENT *newStudent, STUDENT *currentStudent); 
void printStudents(STUDENT *s); 

struct Student 
{ 
    int StudentNumber; 
    char FirstName[BUFSIZ]; 
    STUDENT *left, *right; 
}; 

struct Teacher 
{ 
    int TeacherNumber; 
    char FirstName[BUFSIZ]; 
    TEACHER *left, *right; 
}; 

struct Course 
{ 
    int CourseNumber; 
    char CourseName[BUFSIZ]; 
    int SemesterNumber; 
    COURSE *left, *right; 
}; 

int main() 
{ 
    FILE *db = fopen("DatabaseFile.txt", "r"); 
    char line[BUFSIZ]; 

    STUDENT *newStudent, *currentStudent, *students; 
    students = NULL; 

    if (db != NULL) 
    { 
     while (fgets(line, sizeof(line), db) != NULL) 
     { 
      if (line[0] == 'S') 
      { 
       newStudent = malloc(sizeof(STUDENT)); 

       if (sscanf(line, "S %d %s", &newStudent->StudentNumber, newStudent->FirstName) == 2) 
       { 
        newStudent->left = NULL; 
        newStudent->right = NULL; 

       if (students == NULL) 
       { 
        students = newStudent;  

       } 
       else 
       { 
        currentStudent = students; 

        while(currentStudent) 
        { 
         if (newStudent->StudentNumber != currentStudent->StudentNumber) 
         { 
          if (newStudent->StudentNumber < currentStudent->StudentNumber) 
          { 
           if (currentStudent->left == NULL) 
           { 
            currentStudent->left = newStudent; 
            break; 
           } 
           else 
           { 
            currentStudent = currentStudent->left; 
           } 
          } 
          else 
          { 
           if (currentStudent->right == NULL) 
           { 
            currentStudent->right = newStudent; 
            break; 
           } 
           else 
           { 
            currentStudent = currentStudent->right; 
           } 
          } 
         } 

        } 
       }    

       } 

      } 
     } 
    } 
    printStudents(students); 
} 

它成功地填充樹,之後遍歷它給下面的輸出:

Student Number: 203214 Student Name: Agneta 
Student Number: 208214 Student Name: Janeta 
Student Number: 213363 Student Name: Jill 
Student Number: 215263 Student Name: Hansi 
Student Number: 215363 Student Name: Laurent 
Student Number: 228214 Student Name: James 

現在實踐問題的一部分,也是在給函數所以一切不只是主要方法內運行的動了這一點。

我已經這樣做了,像這樣:

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

typedef struct Student STUDENT; 
typedef struct Teacher TEACHER; 
typedef struct Course COURSE; 

int addStudentToTree(STUDENT *students, STUDENT *newStudent, STUDENT *currentStudent); 
void printStudents(STUDENT *s); 

struct Student 
{ 
    int StudentNumber; 
    char FirstName[BUFSIZ]; 
    STUDENT *left, *right; 
}; 

struct Teacher 
{ 
    int TeacherNumber; 
    char FirstName[BUFSIZ]; 
    TEACHER *left, *right; 
}; 

struct Course 
{ 
    int CourseNumber; 
    char CourseName[BUFSIZ]; 
    int SemesterNumber; 
    COURSE *left, *right; 
}; 

int main() 
{ 
    FILE *db = fopen("DatabaseFile.txt", "r"); 
    char line[BUFSIZ]; 

    STUDENT *newStudent, *currentStudent, *students; 
    students = NULL; 

    if (db != NULL) 
    { 
     while (fgets(line, sizeof(line), db) != NULL) 
     { 
      if (line[0] == 'S') 
      { 
       newStudent = malloc(sizeof(STUDENT)); 

       if (sscanf(line, "S %d %s", &newStudent->StudentNumber, newStudent->FirstName) == 2) 
       { 
        newStudent->left = NULL; 
        newStudent->right = NULL; 
        addStudentToTree(students, newStudent, currentStudent);     
       } 

      } 
     } 
    } 
    printStudents(students); 
} 

int addStudentToTree(STUDENT *students, STUDENT *newStudent, STUDENT *currentStudent) 
{ 

    if (students == NULL) 
    { 
     students = newStudent; 
     return 1; 
    } 
    else 
    { 
     currentStudent = students; 

     while(currentStudent) 
     { 
      if (newStudent->StudentNumber != currentStudent->StudentNumber) 
      { 
       if (newStudent->StudentNumber < currentStudent->StudentNumber) 
       { 
        if (currentStudent->left == NULL) 
        { 
         currentStudent->left = newStudent; 
         return 1; 
        } 
        else 
        { 
         currentStudent = currentStudent->left; 
        } 
       } 
       else 
       { 
        if (currentStudent->right == NULL) 
        { 
         currentStudent->right = newStudent; 
         return 1; 
        } 
        else 
        { 
         currentStudent = currentStudent->right; 
        } 
       } 
      } 

     } 
    } 
    return 0; 
} 

現在的問題棱。我傳入指針'students',並且第一次傳遞它時它是一個空指針,並且正確地被函數中的if語句捕獲。 newStudent變量指向一個內存地址。

這些行後:

if (students == NULL) 
{ 
    students = newStudent; 
    return 1; 
} 

指針「學生」正在指向的實際地址。但是在返回到main方法中的while循環後,'students'指針再次成爲NULL指針。

作爲一個額外的信息,你可以看到,把這些的printf的:

if (students == NULL) 
    { 
     printf("students: %p, newStudent: %p\n",students, newStudent); 
     students = newStudent; 
     printf("students: %p\n",students); 
     return 1; 
    } 

產生這樣的輸出:

students: 0x0, newStudent: 0x7fc6e2001200 
students: 0x7fc6e2001200 
students: 0x0, newStudent: 0x7fc6e2001800 
students: 0x7fc6e2001800 
students: 0x0, newStudent: 0x7fc6e2005200 
students: 0x7fc6e2005200 
students: 0x0, newStudent: 0x7fc6e2005800 
students: 0x7fc6e2005800 
students: 0x0, newStudent: 0x7fc6e2005e00 
students: 0x7fc6e2005e00 
students: 0x0, newStudent: 0x7fc6e2006400 
students: 0x7fc6e2006400 

我真的已在此花費了大量的時間和最終放棄在這裏來問你們所有人。 讓我知道是否還有什麼需要澄清這個問題。

Peter

+0

'void f(STUDENT * p){p = something;}'因爲和void f(int i){i = something;}'沒有任何作用相同的原因, – immibis 2015-02-24 07:15:14

+1

就像您通過值傳遞的任何其他變量一樣,在函數內部對其進行本地更改不會影響函數外部的值。 – 2015-02-24 07:15:59

回答

3

您需要傳遞指針的地址...在這種情況下,參數在棧上創建,並在該函數退出堆棧unwinded和你的論點依然不再有效

int addStudentToTree(STUDENT **students, STUDENT *newStudent, STUDENT *currentStudent); 

調用,比如

addStudentToTree(&學生,newStudent,currentStudent) ;

在功能

做像

* sudents = NULL;

希望幫助

+0

這個伎倆!我一直在嘗試發送地址,但可以看到我需要了解**的工作原理 – Luffen 2015-02-24 08:15:34

0

想象一下:

void func(int var) 
{ 
    var = 1; 
} 

int main() 
{ 
    int var = 0; 
    func(var); 
    // What is the value of 'var' at this point? 
    ... 
} 

如果你上面的問題的答案是1,那麼你或許應該回到基本知識,並從頭學習語言。

如果你也明白,可變var的功能main副本保留其「原生態」的值,那麼你不應該有了解您分配給(副本)可變students內部功能printStudents任何價值的任何問題,將不會在該功能之外生效。

話雖這麼說,這裏有供參考通過這個變量的一般準則:

  1. 添加*在函數聲明的變量的類型 - printStudents(STUDENT** s)
  2. 添加*到每一個參考,你使這個變量裏面的變量功能printStudents
  3. 加上&之前變量在你調用函數的每個地方 - printStudents(&s)
+0

「你應該回到基礎並從頭開始學習語言」這一部分當然沒有冒犯意圖,只是一個幽默(或無幽默,取決於你的解釋)的方式,假設你**做**瞭解手頭的情況... – 2015-02-24 08:06:34

+0

感謝您的回答,我的挑戰是,我認爲我發送了一個因爲我接受了函數定義中的指針addStudentToTree(STUDENT * students) 但是我可以看到我需要閱讀**的工作原理。 你的答案是好的,但我接受了另一個,因爲它是第一個,並解決了問題 彼得 – Luffen 2015-02-24 08:17:07

+0

@Luffen:不客氣,沒有問題哪一個你接受:) – 2015-02-24 08:33:53