试图在结构使用scanf函数时分割故障 [英] Segmentation Fault when trying to use scanf on a struct

查看:106
本文介绍了试图在结构使用scanf函数时分割故障的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我是pretty新的C和我此刻的沮丧以及pretty。这里的code我有:

I'm pretty new to c and I'm pretty frustrated at the moment as well. Here's the code I have:

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函数输入一个值某些原因,它给了我一个分段错误。如果我尝试添加A和在接触式前> FNAME我得到一个错误也是如此。

For some reason when I enter a value for the scanf it gives me a segmentation fault. If I try to add a & in front of the contact->fName I get an error as well.

什么是错的code?

推荐答案

首先,不要担心 - 挫折是正常的开端C :)

First off, don't worry - frustration is normal with beginning C :)

既然你说你是一个初学者,我写了一个pretty长的答复,说明您可能要进行一些其他方面的改进。很抱歉,如果我介绍一些事情你已经知道了。这里有一个总结:

Since you say you're a beginner, I've written a pretty long answer that explains some other improvements you might want to make. Sorry if I cover some things you already know. Here's a summary:


  1. 您将需要分配一些空间,为的char * s到指向(这是什么导致崩溃)

  2. 确保您的malloc检查返回值

  3. 确保问 scanf()的为只读尽可能多的字符,你可以在你的字符串举行。

  4. 无需从malloc的。将返回值

  5. 记住免费()任何你所malloc的-ED。

  1. You'll need to allocate some space for the char*s to point to (this is what's causing the crash)
  2. Make sure you check the return value from malloc
  3. Make sure ask scanf() to only read as many characters as you can hold in your string.
  4. No need to cast the return value from malloc.
  5. Remember to free() anything you've malloc-ed.

在C,一个的char * 表示指针为char。 的char * 常用于字符串,因为你可以索引指针就像他们的阵列 - 例如,假设:


You'll need to allocate some space for the char*s to point to

In C, a char* means "a pointer to a char". char* is commonly used for strings, since you can index pointers like they were arrays - for example, assuming:

 char *a = "Hello";

然后, A [1] 意思是第一个字符炭后指出, A ,在这种情况下'E';

Then, a[1] means "the first char after the char pointed to by a, in this case 'e';

您有这个code:

contactInfo *contact;
contact = (contactInfo *) malloc (sizeof(contactInfo));

在这一点上,你声明一个指向一个结构CONTACTINFO及分配合适大小的内存给它。但是,结构内部的指针,目前没有指向任何东西 - 所以当它调用你的程序崩溃 scanf()的。您还需要为你即将读取字符分配空间,例如:

At this point, you've declared a pointer to a contactInfo struct, and allocated memory of the right size to it. However, the pointers inside the structure currently don't point to anything - so your program is crashing when it calls scanf(). You need to also allocate space for the characters you're about to read, for example:

contact->fName = malloc(sizeof(char) * 10);

将为10个字符分配空间。你需要为每个的char * 在结构中做到这一点。

一对夫妇旁白的,我不想让你担心太多:

A couple of asides that I don't want you to worry about too much:


  • 在C,的sizeof(char)的始终为1,所以你可以写的malloc(10),但在我看来这是不太可读。

  • 您也可以这样做:

  • In C, sizeof(char) is always 1, so you could have written malloc(10), but in my opinion that's less readable.
  • You can also do something like:

contact->fName = malloc(sizeof(*(contact->fName)) * 10);

这是稳健的 FNAME 类型的变化 - 你总是因为种种的10分配足够的空间 FNAME 点。

This is robust to changes in the type of fName - you'll always allocate enough space for 10 of whatever fName points to.

现在回到正轨 - 您也应该检查从的返回值的malloc()

Back on track now - you should also check the return value from malloc():

contact->fName = malloc(sizeof(char) * 10);
if(contact->fName == NULL) {
   // Allocation failed 
}

在某些情况下,你也许可以从失败中恢复分配(比如,试图
中重新分配,但要求更少的空间),但与启动:

In some cases, you might be able to recover from a failed allocation (say, trying to allocate again, but asking for less space), but to start with:

contact->fName = malloc(sizeof(char) * 10);
if(contact->fName == NULL) {
   printf(stderr,"Allocation of contact->fName failed");
   exit(EXIT_FAILURE);
}

大概是罚款。许多程序员会写 malloc的一个包装()执行此错误检查他们,让他们不必再担心。

Is probably fine. Many programmers will write a wrapper for malloc() that does this error checking for them, so that they no longer have to worry about it.

请注意,一旦你分配的说,在 FNAME 10字符scanf()的可能会读太多字符。您可以显式地告诉scanf函数的极限写入%NS其中N是字符的最大数量在您的字符串(减1为空终止末)。所以,如果你已经分配了10个字符,那么你应该写:

Note that once you've allocated say 10 char in fName, scanf() might read too many characters. You can explictly tell scanf the limit by writing "%Ns" where N is the maximum number of characters in your string (minus 1 for the null terminator at the end). So, if you've allocated 10 characters, then you should write:

scanf("%9s", contact->fName);

无需从投malloc的返回值。

最后一点 - 你不需要投用C 的malloc的返回值,所以我大概写:

No need to cast the return value from malloc.

One final point - you don't need to cast the return value of malloc in C, so I'd probably write:

 contact =  malloc (sizeof(contactInfo));

记住免费()任何你所malloced

您可能已经这样做了,但每次的malloc()任何事情,请确认你已经相应免费()在code一旦你用它做。这告诉操作系统,它可以有记忆回来了。所以,如果你有什么地方

Remember to free() anything you've malloced

You might be doing this already, but every time you malloc() anything, make sure you have a corresponding free() in your code once you're done with it. This tells the operating system it can have the memory back. So, if you've got somewhere

 contact =  malloc (sizeof(contactInfo));

后来,当你与该联系人做,你就需要有这样的:

Later on, when you're done with that contact, you'll need to have something like:

 free(contact);

以避免内存泄漏。

to avoid memory leaks.

只要你释放的东西,你不允许任何更多的访问。所以,如果你的联系人里面malloced字符串,你得先释放他们:

As soon as you've freed something, you aren't allowed to access it any more. So, if you've malloced strings inside the contact, you'll have to first free them:

 free(contact->fName);  // doing this in the other order might crash
 free(contact);  

有几件事情要记住免费的:

A few things to remember about free:


  1. 您无法释放任何两次。为了避免这种情况,一个好的做法是写:

  1. You can't free anything twice. To avoid this, a good practice is to write:

 if(contact != NULL) free(contact); 
 contact = NULL;

如果你写的这样,那么你就需要在创建他们也初始化所有的指针为NULL。当您创建在他​​们的指针结构,一个简单的方法做,这是使用 释放calloc() 代替的malloc()以创建的结构,因为释放calloc()返回内存,这始终是零。

If you write this way, then you'll need to also initialise all pointers to NULL when you create them. When you create structs that have pointers in them, an easy way to do this is to use calloc() instead of malloc() to create the struct, since calloc() returns memory which is always zeroed.

在你的程序退出时,所有的内存被释放回操作系统。这意味着,你不这样做的技术上的需要免费()的东西都是围绕该计划的生命周期。不过,我建议你进入释放你malloced一切的习惯,否则你会忘记有一天,当这一点很重要。

When your program exits, all memory is released back to the operating system. This means you don't technically need to free() things that are around for the lifetime of the program. However, I'd recommend getting into the habit of freeing everything you've malloced, because otherwise you'll forget one day when it's important.

作为一个评论者指出了另一个答案,用幻数(在code号硬codeD)一般是不好的做法。在我给你上面的例子,我已经很难codeD10到程序的字符串的大小。然而,这是更好地做一些事情,如:


Further improvements

As a commenter points out on another answer, using magic numbers (numbers hard coded in your code) is generally bad practice. In the examples I've given you above, I've hard coded "10" into the program as the size of the string. However, it's better to do something like:

#define FNAME_MAX_LENGTH 10

再后来去:

malloc(sizeof(char) * FNAME_MAX_LENGTH);

该做的好处是,如果你需要的任何地方改变字符串的大小,你可以在一个地方改变它。它还prevents您偶然在一个地方输入100或1,造成潜在的严重,难以发现错误。

This has the advantage that if you need to change the size of the string anywhere, you can change it in just one place. It also prevents you accidentally typing 100 or 1 in one place, causing a potentially serious, hard-to-find bug.

当然,现在你已经有了一个的#define 的长度,你需要更新 scanf()的调用我们指定的长度。然而,由于 scanf()的所需要的长度 - 1,您将无法使用的#define 来指定长度(至少,不以任何好的可读的方式)。

Of course, now that you've got a #define for the length, you'll need to update the scanf() call where we specify the length. However, since scanf() needs the length - 1, you won't be able to use the #define to specify the length (at least, not in any nice readable way).

因此​​,您可能会感兴趣的 与fgets() ,它读取到指定长度-1(或直到行的结束 - 以先到为准)。然后,你可以这样做:

Consequently, you might be interested in fgets(), which reads up to a specified length -1 (or until the end of the line - whichever is first). You could then do:

fgets(contact->fName,FNAME_MAX_LENGTH,stdin);

而不是 scanf()的电话。另一个很好的理由做出了这种变化 scanf()的可以的一种痛苦的。

instead of the scanf() call. Another good reason to make this change is that scanf() can be kind of a pain.

因此​​,除了上面的总结:

So, in addition to the summary above:


  1. 使用#定义字符串的长度可避免的问题,使其更容易稍后更改您的code。

  2. 与fgets()是很容易,使用scanf()的,并且与使用<$更兼容C $ C>的#define 的字符串长度。

  1. Using a #define for the length of the string can avoid problems and make it easier to change your code later.
  2. fgets() is easier to use than scanf(), and is more compatible with using a #define for the string length.

这篇关于试图在结构使用scanf函数时分割故障的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆