学习C,会欣赏有关此解决方案工作原理的信息

Kei*_*fer 7 c segmentation-fault

这是我用C编写的第一件事,所以请随意指出它的所有缺陷.:)我的问题是这样的:如果我按照我认为最干净的方式编写程序,我会得到一个破碎的程序:

#include <sys/queue.h> 

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

/* Removed prototypes and non related code for brevity */

int
main()
{
    char    *cmd = NULL; 
    unsigned int acct = 0; 
    int amount = 0; 
    int done = 0; 

    while (done==0) {
        scanf ("%s %u %i", cmd, &acct, &amount);

        if (strcmp (cmd, "exit") == 0)
            done = 1;
        else if ((strcmp (cmd, "dep") == 0) || (strcmp (cmd, "deb") == 0))
            debit (acct, amount);
        else if ((strcmp (cmd, "wd") == 0) || (strcmp (cmd, "cred") == 0))
            credit (acct, amount);
        else if (strcmp (cmd, "fee") == 0)
            service_fee(acct, amount);
        else
            printf("Invalid input!\n");
    }
    return(0);
}

void
credit(unsigned int acct, int amount)
{
}

void
debit(unsigned int acct, int amount)
{
}

void
service_fee(unsigned int acct, int amount)
{
}
Run Code Online (Sandbox Code Playgroud)

就目前而言,上面在编译时没有产生错误,但在运行时给了我一个段错误.我可以通过在调用scanf和strcmp时通过引用更改程序来传递cmd来解决这个问题.段错误消失,在编译时每次使用strcmp时都会被警告取代.尽管有警告,但受影响的代码仍可正常工作.

警告:从不兼容的指针类型传递'strcmp'的arg 1

作为一个额外的好处,修改scanf和strcmp调用允许程序进展足够远以执行return(0),此时事件与Abort陷阱崩溃.如果我换出return(0)退出(0),那么一切都按预期工作.

这让我有两个问题:为什么原始程序错了?我怎样才能比我更好地修复它?

关于需要使用退出而不是返回的一点让我特别困惑.

sam*_*moz 11

这是因为scanf语句而发生的.

看看cmd是如何指向NULL的.当scanf运行时,它会写入cmd的地址,该地址为NULL,从而生成段错误.

解决方案是为cmd创建缓冲区,例如:

char cmd[20];
Run Code Online (Sandbox Code Playgroud)

现在,您的缓冲区可以容纳20个字符.但是,如果用户输入超过20个字符,您现在需要担心缓冲区溢出.

欢迎来到C.

编辑:此外,请注意您的信用卡,借记卡和服务费功能将无法按预期编写.这是因为参数是按值传递的,而不是通过引用传递的.这意味着在方法返回后,将丢弃任何更改.如果您希望它们修改您提供的参数,请尝试将方法更改为:

void credit(unsigned int*acct,int*amount)

然后称他们为:

credit(&acct, &amt);
Run Code Online (Sandbox Code Playgroud)

这样做会通过引用传递参数,这意味着即使在函数返回后,您在credit函数内所做的任何更改都会影响参数.

  • 喜欢这个答案中的最后一句话;) (2认同)
  • 值得注意的是接下来的问题*"那么如何在不对输入长度进行任意限制的情况下管理这个问题?"*并且这个问题已在SO上多次回答.简短的回答是使用`fgets`或`getline`,并且可以找到关于这些工作原理的一些说明http://stackoverflow.com/questions/2532425/c-read-line-from-file-without-knowing- the-line-length/2532450#2532450其中很多. (2认同)

dcp*_*dcp 7

你没有为cmd分配内存,所以就是这样NULL.

尝试用一些空间声明它:

char cmd[1000];
Run Code Online (Sandbox Code Playgroud)


小智 5

正如其他人所指出的那样,你还没有为scanf分配任何内容.但是你也应该测试scanf的返回值:

if ( scanf ("%s %u %i", cmd, &acct, &amount) != 3 ) {
   // do some error handling
}
Run Code Online (Sandbox Code Playgroud)

scanf函数返回成功转换的次数,因此如果有人在期望您希望能够检测并处理它的整数时键入XXXX.但坦率地说,使用scanf()的用户界面代码永远不会成为这种事情的证明.scanf()实际上是用于读取格式化文件,而不是来自人类的随机输入.