为什么我要执行此代码的细分故障?

发布于 2025-01-19 14:39:33 字数 346 浏览 4 评论 0原文

我试图找出这段代码的问题:

int main(int argc, char *argv[])
{
    char *s;
    scanf("%s\n", s);

    char *t = malloc(sizeof(*s) + 1);

    strcpy(t, s);
    t[0] = toupper(t[0]);
    printf("s: %s\n", s);
    printf("t: %s\n", t);

    free(t);
    return 0;
}

我试图将输入的第一个字母大写,例如将 hi! 更改为 Hi!

I'm trying to figure out the issue with this code:

int main(int argc, char *argv[])
{
    char *s;
    scanf("%s\n", s);

    char *t = malloc(sizeof(*s) + 1);

    strcpy(t, s);
    t[0] = toupper(t[0]);
    printf("s: %s\n", s);
    printf("t: %s\n", t);

    free(t);
    return 0;
}

I was trying to upper case the first alphabet of my input to get for example hi! changed into Hi!.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

琉璃繁缕 2025-01-26 14:39:33
  1. 您在char*上使用scanf,而无需先分配内存。这可能会导致细分故障。实际上,以下代码:

     #include< stdio.h>
    int main()
    {
        char* str;
        scanf(“%s”,str);
        printf(“%s \ n”,str);
        返回0;
    }
     

    有时确实会出现分割故障。取而代之的是,如果要避免malloc,则可以使用char数组而不是char*。您可以使用fgets而不是scanf来防止写入界限,也可以使用scanf本身来检查:

      char s [100];
    if(scanf(“%99S”,s)!= 1){ / *错误 * /}
     

    在您的代码中,在%s之后,您在scanf语句中有一个\ n, 't打算这种行为)。您可以在此处查看它的作用:


  2. 其次,在为t分配内存时,您使用的是sizeof(*s),它只是size> sizeof(char)定义为1。相反,您应该使用strlen(s)+1,它将分配一个字节,而不是s的长度。另外,还建议检查t == null

  3. 在调用之前在平台上签名。有关此答案的更多信息: https://stackoverflow.com/a/21805970/18639286 (尽管问题是一个C ++问题,答案实际上引用C标准规格)


我已将上述更改编辑为您的代码以获取以下内容:

int main (int argc,char* argv[])
{

    char s[100];
    if(scanf("%99s",s)!=1)
    {
       fprintf(stderr, "Invalid or missing input\n");
       // scanf should have returned 1 if it successfully read 1 input
    }
    char *t = malloc(strlen(s) + 1); // to store the letters + '\0' at the end
    if(t==NULL)
    {
       fprintf(stderr, "Memory allocation failed\n");
       exit(1);
    }

    strcpy(t, s);
    t[0] = toupper((unsigned char)t[0]);
    printf("s: %s\n", s);
    printf("t: %s\n", t);

    free(t);
    return 0;

}

一些额外的积分:

您也可以使用fgets而不是scanf
fgets(S,100,STDIN);作为fgets确实绑定了检查。

另外,fgets读取直到线/文件的结尾或缓冲区已满,因此它将通过输入中的空格读取,但是scanf将停止在空间。或正如Ted Lyngmo在评论中指出的那样, scanf带有%s读取一个单词,而fgets读取一行

但是,即使您打算只读一个单词,也可以使用fgets,然后使用sscanf来读取使用fgets的字符串中的第一个单词。示例:

char buffer[20];
char str[sizeof buffer]=""; //initialize with an empty string
if(fgets(buffer, sizeof buffer, stdin)==NULL)
{
  fprintf(stderr, "Error reading input\n");
  exit(1);
}
if(sscanf(buffer, "%s", str)!=1)
{
  // if str was not read
  fprintf(stderr, "String not read\n");
  exit(1);
}
// DO stuff with str 

在这里,您不需要使用%19S,因为我们知道buffer的大小。

  1. You are using scanf on a char* without first allocating memory to it. This may lead to segmentation fault. In fact, the following code :

    #include<stdio.h>
    int main()
    {
        char* str;
        scanf("%s", str);
        printf("%s\n", str);
        return 0;
    }
    

    does give segmentation fault sometimes. Instead you can use a char array instead of a char* if you want to avoid malloc before scanf . You can use fgets instead of scanf to prevent writing out of bounds or you can check with scanf itself like this:

    char s[100];
    if(scanf("%99s",s) != 1) { /* error */ }
    

    Also in your code, you have a \n after %s in the scanf statement, that I have removed(assuming you didn't intend this behaviour) . You can see what that does here: Using "\n" in scanf() in C

  2. Secondly, in allocating memory for t, you are using sizeof(*s) which is just sizeof(char) which is defined to be 1. Instead, you should be using strlen(s)+1 which will allocate one more byte than the length of s which should work fine. Also, checking if t==NULL is also recommended.

  3. Before calling toupper the argument must be type-casted into an unsigned char to avoid the risks of undefined behaviour if the char type is signed on the platform. More on this can be found on this answer: https://stackoverflow.com/a/21805970/18639286 (Though the question was a C++ question, the answer actually quotes C standard specifications)

I have edited the above changes into your code to get the following:

int main (int argc,char* argv[])
{

    char s[100];
    if(scanf("%99s",s)!=1)
    {
       fprintf(stderr, "Invalid or missing input\n");
       // scanf should have returned 1 if it successfully read 1 input
    }
    char *t = malloc(strlen(s) + 1); // to store the letters + '\0' at the end
    if(t==NULL)
    {
       fprintf(stderr, "Memory allocation failed\n");
       exit(1);
    }

    strcpy(t, s);
    t[0] = toupper((unsigned char)t[0]);
    printf("s: %s\n", s);
    printf("t: %s\n", t);

    free(t);
    return 0;

}

Some extra points:

You can also use fgets instead of scanf :
fgets(s, 100, stdin); as fgets does bound checking.

Also, fgets reads till end of line/file or till the buffer is full, so it will read past the spaces in input, But scanf will stop at a space. Or as Ted Lyngmo pointed out in the comments, scanf with %s reads a word, while fgets reads a line.

But, even if you intend to read only a word, you can use fgets and then use sscanf to read the first word from the string with which you used fgets. Example:

char buffer[20];
char str[sizeof buffer]=""; //initialize with an empty string
if(fgets(buffer, sizeof buffer, stdin)==NULL)
{
  fprintf(stderr, "Error reading input\n");
  exit(1);
}
if(sscanf(buffer, "%s", str)!=1)
{
  // if str was not read
  fprintf(stderr, "String not read\n");
  exit(1);
}
// DO stuff with str 

Here, you don't need to use %19s because we know the size of buffer.

风吹雪碎 2025-01-26 14:39:33

作为已经很棒的答案的旁注,我必须推荐GNU调试器(不久GDB)。

运行“ gdb [program name]”,该程序应与-G flag一起编译。在交互式环境中,您可以通过键入r来运行该程序,该程序可能会产生一些有用的信息。键入“ b&lt; number&gt;“在运行时指定休息时间,然后键入“ s [number]”程序中的许多行。

GDB有很多方法可以提取有关跑步程序的信息,我建议大量建议阅读其中的文档。

As a sidenote to the already great answer, I must recommend GNU Debugger (shortly gdb).

Run "gdb [program name]", the program should be compiled with the -g flag. In the interactive environment, you can run that program by typing r which may yield some useful information. Typing "b <number>" to specify a break in the runtime, then type "s [number]" a number of lines ahead in the program.

There are plenty of ways with gdb to extract information about the running program, I'd heavily recommend reading the docs on it.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文