【问题标题】:Why is this scanf statement causing Segmentation Faults?为什么这个 scanf 语句会导致分段错误?
【发布时间】:2015-06-12 16:23:55
【问题描述】:

我已经把头撞在墙上一个小时了,我正在失去理智...我有一段代码(是的,这是家庭作业)会引发分段错误,除非我注释掉其中一个我的 scanf 语句。我尝试使用 gdb 来调试问题,但直到今天我还没有真正了解这一点。

代码如下:

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


char * creditCard(char * ccNumber){
  char * lastFour;

  lastFour = (ccNumber + strlen(ccNumber) - 4);

  return lastFour;
}

void zipCode(int zip){
  printf("The zip code entered is: %d\n", zip);

}

int fuelGrade(int grade){

}

int main(void){
  char * ccNumber = NULL;
  int zip = 0;
  int gasGrade = 0;

  printf("Please Enter Credit Card Number: ");
  scanf("%s", ccNumber);

  printf("Please Enter Your Billing Zip Code: ");
  scanf("%d", &zip);

  printf("Select your Fuel Grade.\n Unleaded(1) Plus(2) Premium(3): ");
  scanf("%d", &gasGrade);


  ccNumber = creditCard(ccNumber);
  printf("****-****-****-%s\n", ccNumber);

  zipCode(zip);

  return 0;
}

当我按原样编译和运行时,我得到以下信息:

Please Enter Credit Card Number: 123413515
Please Enter Your Billing Zip Code: Select your Fuel Grade.
Unleaded(1) Plus(2) Premium(3): 1
Segmentation fault

输入邮政编码被跳过,我在输入任何燃料等级后立即得到一个段错误。但是,如果我注释掉 scanf("%d", &gasGrade); 行,代码运行良好。

最初我没有初始化变量,并且我的代码组织方式略有不同,但我似乎无法找到解决这个问题的正确方法。 我在这里做错了什么?

感谢您的帮助!

【问题讨论】:

  • ccnumber 变量需要指向分配的内存区域(比信用卡号的最大长度长)建议,在声明 ccnumber 的地方,追加:= malloc(MAX_CC_NUM_LEN) 或类似的东西.请记住始终检查 (!=NULL) 从 malloc()(和函数系列)返回的值,以确保操作成功。

标签: c segmentation-fault scanf


【解决方案1】:

因为通过使用ccNumber = NULL 执行scanf("%s", ccNumber);,您正在取消引用NULL 指针。

scanf()"%s" 说明符需要一个指向有效内存的指针,它可以在其中写入扫描的数据,您正在传递一个 NULL 指针,它不检查指针是否为 NULL,因此它是取消引用 NULL 指针。

你需要有效的内存,所以在这种情况下你可以使用堆栈,像这样

char  buffer[100];
char *ccNumber;
if (scanf("%99s", buffer) != 1)
    problemScanning_buffer_DoNotUse_buffer_In_TheFollowingCode();
ccNumber = creaditCard(buffer);

请注意上面的99,它可以防止buffer 溢出,并且您必须始终检查scanf() 的返回值以防止出现未定义行为。

【讨论】:

  • 为什么scanf("%d",&gasGrade);不在这里?感谢您的帮助,我会在一分钟内看看它是否有效
  • 因为取消引用 NULL 指针是未定义的行为,而结果行为取决于程序中的其他内容。
  • 这是有道理的。谢谢你的解释!
【解决方案2】:

您要么必须使用 malloc 为 ccNumber 分配内存,要么将其定义为数组 char ccNumber[17](16 位数字 + \0 字符)。现在它是一个指向您初始化为 NULL 的单个字符的指针。

【讨论】:

    【解决方案3】:

    你没有为 cc Number 分配内存(ccNumber 为 NULL)

    读取数字时必须清除换行符,但要使用 scanf 读取另一个值,会自动读取输入缓冲区 (stdin) 中的 '\n'。

    printf("Please Enter Your Billing Zip Code: ");
    scanf("%d", &zip);
    

    变化:

    scanf("%d", &zip);
    

    收件人:

    scanf("%d%*c", &zip);
    

    【讨论】:

    • "读取数字时必须清除换行符"...这很有趣,因为my manual 另有说明:"输入空白字符(由 isspace() 指定)应被跳过,除非转换规范包含 [、c、C 或 n 转换说明符。"
    • 有空格,是换行。 Scanf 未读取换行符 ('\n')。您的手册完全错误。
    • Opengroup 错了? the C standard呢?
    • '\n' 是否包含在 isspace 返回 true 的集合中?查看 C 标准...它比您的 K&R 书更可信。我是否有超过 5k 的代表回答了 337 个答案,其中 298 个答案中有 c 标签用于欺骗他人?我的消息来源是可信的。
    • 是你说 '\n' 因为 isspace 而被忽略,而不是我!!!!不管你有多少k个答案/票,这与编程知识无关,或者至少知道是哪个程序的语言。
    猜你喜欢
    • 2015-05-15
    • 2017-08-18
    • 1970-01-01
    • 2016-09-24
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多