2012-09-09 38 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