我很新的C和我此刻非常沮丧,以及。 下面是我的代码:
typedef struct {
char* fName;
char* lName;
char* pNum;
char* address;
char* email;
} contactInfo;
void addContact(){
contactInfo *contact;
contact = (contactInfo *) malloc (sizeof(contactInfo));
printf("\n[Add a contact]\nFirst Name: ");
scanf("%s", contact->fName);
printf("%s", contact->fName);
}
出于某种原因,当我输入一个值scanf是它给了我一个分段错误。 如果我尝试在前面加上一个与该非接触> FNAME我得到一个错误也是如此。
有什么不对的代码?
首先,不要担心 - 挫折是正常的开端C :)
既然你说你是一个初学者,我写了一个很长的答案,说明您可能要进行一些其他方面的改进。 很抱歉,如果我讨论一些事情,你已经知道了。 这里有一个总结:
- 你需要分配一些空间,为
char*
s到指向(这是什么导致的崩溃) - 请务必检查从malloc的返回值
- 确保问
scanf()
为只读尽可能多的字符,你可以在你的字符串持有。 - 无需通过malloc将返回值。
- 记住
free()
否则您的malloc-ED。
你需要分配一些空间,为char*
s到指向
在C中, char*
意思是“一个指向一个char”。 char*
常用于字符串,因为你可以索引指针像他们的阵列-例如,假设:
char *a = "Hello";
然后, a[1]
是指“第一char
之后的char指向a
,在这种情况下'e'
;
你有这样的代码:
contactInfo *contact;
contact = (contactInfo *) malloc (sizeof(contactInfo));
在这一点上,你声明的指针,CONTACTINFO结构和分配大小合适的内存给它。 然而,结构内部的指针,目前没有指向任何东西-所以你的程序崩溃时,它调用scanf()
你还需要为你即将读,例如角色分配空间:
contact->fName = malloc(sizeof(char) * 10);
将10个字符分配空间。 你需要为每一个做到这一点char*
的结构。
一对夫妇旁白的,我不想让你担心太多:
请务必检查从malloc的返回值
回到现在的轨道上-你也应该检查从返回值malloc()
contact->fName = malloc(sizeof(char) * 10);
if(contact->fName == NULL) {
// Allocation failed
}
在某些情况下,你也许能够从失败中恢复分配(比如,尝试再次分配,但要求更少的空间),但开始:
contact->fName = malloc(sizeof(char) * 10);
if(contact->fName == NULL) {
printf(stderr,"Allocation of contact->fName failed");
exit(EXIT_FAILURE);
}
可能是罚款。 许多程序员会写一个包装malloc()
这是否错误检查他们,让他们不再担心了。
确保你只问scanf()
读取尽可能多的字符,你可以在你的字符串持有。
需要注意的是,一旦你分配说10字符在fName
, scanf()
可能会读太多的字符。 您可以显式地告诉scanf函数的极限通过写"%Ns"
,其中N是在你的字符串中的字符的最大数量(减1为空终止末)。 所以,如果你已经分配了10个字符,那么你应该写:
scanf("%9s", contact->fName);
无需通过malloc将返回值。
最后一点- 你不需要投用C的malloc的返回值 ,所以我可能会写:
contact = malloc (sizeof(contactInfo));
记住free()
什么你malloced
您可能已经这样做了,但每一次你malloc()
什么,请确保您有相应free()
在你的代码,一旦你用它做。 这告诉操作系统它可以有记忆回来了。 所以,如果你有什么地方
contact = malloc (sizeof(contactInfo));
后来,当你与该联系人完成的,你需要有类似:
free(contact);
以避免内存泄漏。
只要你释放的东西,你不能访问它了。 所以,如果你已经在接触中malloced串,你必须先释放他们:
free(contact->fName); // doing this in the other order might crash
free(contact);
有几件事情要记住免费:
你不能释放任何的两倍。 为了避免这种情况,一个好的做法是这样写:
if(contact != NULL) free(contact); contact = NULL;
如果你写这样,那么你就需要在创建他们也初始化所有的指针为NULL。 当您创建在他们的指针结构,一个简单的方法来做到这一点是使用calloc()
代替malloc()
来创建结构,因为calloc()
返回存储器,它始终是零。
当你的程序退出时,所有的内存被释放回操作系统。 这意味着你没有在技术上需要free()
的东西都是围绕对程序的生命周期。 不过,我建议你进入释放你malloced一切的习惯,否则你会忘记有一天,当这一点很重要。
进一步改进
作为一个评论者指出了另一个答案,使用幻数(代码中的硬编码数)一般是不好的做法。 在我给你上面的例子中,我硬编码“10”到程序的字符串的大小。 然而,这是更好地做一些事情,如:
#define FNAME_MAX_LENGTH 10
再后来去:
malloc(sizeof(char) * FNAME_MAX_LENGTH);
这样做的好处是,如果你需要的任何地方改变字符串的大小,你可以在一个地方改变它。 它还可以防止你不小心在一个地方输入100或1,造成潜在的严重,难以发现错误。
当然,现在你已经有了一个#define
为长度,你需要更新scanf()
调用我们指定的长度。 然而,由于scanf()
需要的长度- 1,您将无法使用#define
指定长度(至少,不能以任何好的可读的方式)。
因此,你可能会感兴趣的fgets()
它读取了特定长度-1(或直到该行结束-以先到为准)。 然后,你可以这样做:
fgets(contact->fName,FNAME_MAX_LENGTH,stdin);
而不是scanf()
调用。 另一个很好的理由让这个变化是scanf()
可以一种痛苦 。
那么,除了上面的总结:
- 使用该字符串的长度的#define可避免的问题,并使其更容易在以后更改您的代码。
-
fgets()
是更容易使用比scanf()
,并且与使用更兼容#define
为字符串长度。
按照从@AdamMihalcin的建议,我给一个几乎完整的代码,我希望能为您服务作为参考。
几点需要注意:
的返回值malloc()
应该进行检查。 因为malloc()
从堆获取内存,如果没有足够的内存,那么malloc()
可能返回NULL
。 要了解更多关于malloc
,你可以阅读它的手册页- man malloc
所有malloc
“版内存必须是free
”版。
scanf()的和与fgets()之间的区别和Ç - scanf()的VS得到()VS与fgets()解释了为什么fgets()
优于scanf()
代码如下:
#include <stdio.h>
#include <stdlib.h>
/*
define the length of each filed
in the contactInfo struct
*/
#define L_fName 10
#define L_lName 10
#define L_pNum 10
#define L_address 25
#define L_email 15
typedef struct {
char* fName;
char* lName;
char* pNum;
char* address;
char* email;
} contactInfo;
contactInfo * release_ci(contactInfo * contact)
{
if (contact == NULL) return NULL;
free(contact->fName);
free(contact->lName);
free(contact->pNum);
free(contact->address);
free(contact->email);
free(contact);
return NULL;
}
contactInfo * alloc_ci()
{
contactInfo *contact;
if ((contact = malloc(sizeof(contactInfo))) == NULL) {
printf("ERROR: unable to allocate memory for contactInfo \n");
goto free_and_fail;
}
if ((contact->fName = malloc(sizeof(char) * L_fName)) == NULL) {
printf("ERROR: unable to allocate memory for fName\n");
goto free_and_fail;
}
if ((contact->lName = malloc(sizeof(char) * L_lName)) == NULL) {
printf("ERROR: unable to allocate memory for lName\n");
goto free_and_fail;
}
if ((contact->pNum = malloc(sizeof(char) * L_pNum)) == NULL) {
printf("ERROR: unable to allocate memory for pNum\n");
goto free_and_fail;
}
if ((contact->address = malloc(sizeof(char) * L_address)) == NULL) {
printf("ERROR: unable to allocate memory for address\n");
goto free_and_fail;
}
if ((contact->email = malloc(sizeof(char) * L_email)) == NULL) {
printf("ERROR: unable to allocate memory for email\n");
goto free_and_fail;
}
return contact;
free_and_fail:
release_ci(contact);
return NULL;
}
int main()
{
contactInfo *ci = alloc_ci();
if (!ci) return -1;
printf("Enter fName : ");
fgets (ci->fName, L_fName, stdin);
printf("Enter lName : ");
fgets (ci->lName, L_lName, stdin);
printf("Enter pNum : ");
fgets (ci->pNum, L_pNum, stdin);
printf("Enter address : ");
fgets (ci->address, L_address, stdin);
printf("Enter email : ");
fgets (ci->email, L_email, stdin);
/* TODO: validation for all the input fields */
release_ci(ci);
return 0;
}
你应该对所有分配内存char *
在你的结构。
例如:
contact->fName = malloc(sizeof(char) * 10);
此外,你应该检查返回值malloc()