2012-09-09 82 views
1

所以我想學C,現在,我有一些基本的結構問題,我想搞清楚:Ç - 結構體和指針基本問題

基本上圍繞這個代碼片段一切中心:

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

#define MAX_NAME_LEN 127 

typedef struct { 
    char name[MAX_NAME_LEN + 1]; 
    unsigned long sid; 
} Student; 

/* return the name of student s */ 
const char* getName (const Student* s) { // the parameter 's' is a pointer to a Student struct 
    return s->name; // returns the 'name' member of a Student struct 
} 

/* set the name of student s 
If name is too long, cut off characters after the maximum number of characters allowed. 
*/ 
void setName(Student* s, const char* name) { // 's' is a pointer to a Student struct |  'name' is a pointer to the first element of a char array (repres. a string) 
    char temp; 
int i; 
for (i = 0, temp = &name; temp != '\0'; temp++, i++) { 
    *((s->name) + i) = temp; 
} 

/* return the SID of student s */ 
unsigned long getStudentID(const Student* s) { // 's' is a pointer to a Student struct 
    return s->sid; 
} 

/* set the SID of student s */ 
void setStudentID(Student* s, unsigned long sid) { // 's' is a pointer to a Student struct | 'sid' is a 'long' representing the desired SID 
    s->sid = sid; 
} 

我已經評論了代碼,以鞏固我對指針的理解;我希望他們都準確。

另外,我有另一種方法,

Student* makeAndrew(void) { 
    Student s; 
    setName(&s, "Andrew"); 
    setStudentID(&s, 12345678); 
    return &s; 
} 

,我敢肯定是錯誤的以某種方式......我也覺得我的setName被錯誤地執行。

任何指針? (無雙關語)

+0

不用手動複製,使用例如'strcpy'。 –

+0

'setName'不檢查輸入字符串長度,所以它可能會崩潰爲足夠長的輸入字符串。你需要'temp'='\ 0'&&我 Vlad

回答

2

在您的「另一種方法」中,您在本地聲明Student s,它將動態分配空間(通常位於堆棧上),並在完成時返回該地址。

但是,這個堆棧空間將在返回時釋放,所以不能保證數據沒有損壞 - 事實上它可能是!

在調用你的方法申報Student s,並通過指針makeAndrew:

void makeAndrew(Student *s) { 
    setName(s, "Andrew"); 
    setStudentID(s, 12345678); 
} 


... 

Student s; 
makeAndrew(&s); 

... 
+0

爲了使事情清楚起見,您的'makeAndrew'實現中的'return'語句試圖返回一個雙精度指針,而不是必需的。 –

+0

謝謝@Deepanjan - 原來的複製/粘貼錯誤現在更正了 – Andrew

3

這是非常錯誤的。如果你堅持不使用strcpy做這樣的事情(未測試)

int iStringLength = strlen(name); 
for (i = 0; i < iStringLength; i++) { 
    s->name[i] = name[i]; 
} 

但要確保長度不超過你的陣列尺寸長。

這也是錯誤的

Student* makeAndrew(void) { 
    Student s; 
    setName(&s, "Andrew"); 
    setStudentID(&s, 12345678); 
    return &s; 
} 

因爲當函數退出s對象被銷燬 - 這是函數的局部範圍內,但你返回一個指針。因此,如果您嘗試使用此指針訪問結構,它將不再有效,因爲實例不再存在。如果你想這樣做,你應該使用malloc動態分配它。或者,不要返回指針,並使用@Andrew的替代選項。

+0

在準備好的chaps和Chapesses上的向下投票,但是請不要鼓勵新的C用戶使用malloc() - 有很多原因,爲什麼它是borked我們真的應該勸阻它的使用!至少直到他們意識到陷阱 – Andrew

+1

@Andrew,這是一個愚蠢的事情要說:如何獲得動態分配的內存? – huon

+1

你不能downvote評論可以嗎? – mathematician1975

0

您的功能makeAndrew返回指向局部變量的指針。它只在範圍結束之前有效,所以一旦函數結束,它將在內存被覆蓋時改變 - i。即幾乎立即。你將不得不動態分配它(使用Student *s = new Student;,或者如果你真的想堅持純C,Student *s = malloc (sizeof Student);,然後在不需要它之後將它釋放到函數之外,以避免內存泄漏。

或者將它作爲Andrew建議,這是不太容易出錯

0

我會改變makeAndrew()函數只返回一個結構,而不是一個指向結構相對於糾正錯誤的指針返回給一個臨時變量:

Student makeAndrew(void) 
{ 
    Student s; 
    setName(&s, "Andrew"); 
    setStudentID(&s, 12345678); 
    return s; 
} 

Student aStudent = makeAndrew(); 

你的setName對temp有錯誤,應該是char *,因爲你在你的循環中遞增它以指向輸入字符串中的另一個字符。我認爲它也錯過了空終止。正如您在您的評論提到,應該有學生的名字字符數組的溢出檢查:

void setName(Student* s, const char* name) { // 's' is a pointer to a Student struct |  
    // 'name' is a pointer to the first element of a char array (repres. a string) 
    const char *temp; 
    int i; 
    for (i = 0, temp = name; *temp != '\0' && i <= MAX_NAME_LEN; temp++, i++) 
    { 
     *((s->name) + i) = *temp; 
    } 
    s->name[i] = '\0'; 
} 

你可以使用strncpy()函數來簡化的setName:

void setName2(Student *s,const char *name) 
{ 
    #include <string.h> 
    strncpy(s->name, name,MAX_NAME_LEN); 
    s->name[MAX_NAME_LEN] = '\0'; 
} 
+0

我會保留倒票,但我很想理解你的推理,因爲這種方法增加了不必要的開銷 - 儘管優化可能會導致指針被傳遞? – Andrew

+0

@Andrew你指的是哪一個函數? – Scooter

+0

我指的是評論'只是返回一個結構,而不是一個結構的指針' – Andrew