【问题标题】:fgets and strlen in cc中的fgets和strlen
【发布时间】:2013-06-23 02:09:06
【问题描述】:
#include<stdio.h>
#include<stdlib.h>
#include<string.h>

main()
{
    char str[5]={'\0'};
    printf("Initial length before passing = %ld\n",strlen(str));
    input(str);
    printf("Received string = %s\n",str);
    printf("Length after getting input(calling function) = %ld\n",sizeof(str));
}

input(char * buffer)
{
    puts("Enter something: ");
    printf("Initial length after passing = %ld\n",strlen(buffer));

    if ( fgets(buffer, sizeof(buffer), stdin) == NULL )
        return -1;
    else
    {
        printf("Length after getting input(called function)= %ld\n",strlen(buffer));
        return 0;
    }
}

输出 1

Initial length before passing = 0
Enter something: 
Initial length after passing = 0
hello
Length after getting input(called function)= 6
Received string = hello

Length after getting input(calling function) = 5

输出 2

Initial length before passing = 0
Enter something: 
Initial length after passing = 0
helloooooo
Length after getting input(called function)= 7
Received string = hellooo
Length after getting input(calling function) = 5

为什么当我输入不同的输入时它会打印不同的长度?

  1. 在输出 1 和 2 中,为什么我只为 5 个字符分配空间时初始长度为 6?
  2. 为什么输出1和输出2传入前后字符串长度不同?
  3. 在输出 2 中,当我只分配较少空间时,为什么“获取输入后的长度(调用函数)= 7”?

【问题讨论】:

  • 您必须运行 64 位编译。如果不是,input() 中的sizeof(buffer) 将是 4,并且您会看到两个输入序列的字符串 hel。您必须将数组的大小显式传递给函数:extern int input(char *buffer, size_t buflen);,然后在函数内部引用buflen 而不是sizeof(buffer)。其余的基本上是调用未定义的行为;你得到你所得到的,没有理由抱怨,因为你溢出了你的数组。 C 不能保护你免受你自己或你的无知;这是一种苛刻的语言(但也很强大和有趣)。

标签: c arrays string fgets


【解决方案1】:

strlen 应该使用 C 字符串,即以 \0 结尾的字符数组。当你定义:

char str[5];

str 包含垃圾,你很幸运调用strlen 没有导致分段错误。

【讨论】:

    【解决方案2】:

    1) 在输出 1 和 2 中,为什么当我只为 5 个字符分配空间时初始长度为 6?

    您的第一个 strlen(str) 调用甚至没有真正定义,因为您声明了 char str[5] 但没有在其中添加任何内容。所以内容是谁知道的。 strlen(str) 返回 6 的事实只是意味着内存中碰巧有 6 个非零字符,从地址 str 开始,然后遇到 0。

    2) 为什么输出1和输出2都传入和传入后字符串长度不同?

    在获得长度为 6 的随机内存内容后,您将某些内容加载到字符串缓冲区并以零终止它。所以长度变成了真实的东西。

    3) 在输出 2 中,当我分配的空间较少时,为什么“获得输入后的长度(调用函数)= 7”?

    因为您实际上用更长的字符串(长度为 7)超出了分配的空间。你很幸运在那种情况下程序没有崩溃。

    当你在 C 中声明一个缓冲区时,如:

    char str[5];
    

    它所做的只是告诉编译器您要保留 5 个字节的空间来做某事,并且它授权您使用该空间并且仅将该空间用于str。除非您将某些内容放在那里,否则它不一定要在缓冲区中启动任何内容,并且它不会阻止您写入超出您声明的内容。

    请注意,str[5] 不足以容纳“hello”,因为 C 中的字符串以零结尾。所以你需要一个大小为 N+1 的字符缓冲区来保存一个大小为 N 的字符串。当你在 C 中溢出缓冲区时,你的结果将变得不稳定和不可预测。

    【讨论】:

    • 谢谢。在输出 1 中,我只输入了 5 个字符。但是为什么返回前长度是6,返回后怎么变成55呢?
    • @user1762571 代码中有几个问题会导致一些未定义的行为。您将 sizeof(buffer) 传递给 fgets 并且 sizeof(buffer) 将是内存中字符指针的大小,而不是缓冲区的大小。 sizeof 是数据类型的大小,而不是它指向的内容的长度(如果是指针)。我不确定您系统上的指针有多大,所以我不确定 fgets 试图读取什么。但是由于 str[5] 的缓冲区溢出问题,它不会保存“hello”加上尾随的 0,您可能会得到很多意想不到的行为。
    【解决方案3】:
    char str[5];
    printf("Initial length before passing = %ld\n",strlen(str));
    

    strlen 返回指定字符串的长度,而不是缓冲区的大小。您没有将 str 初始化为任何内容,因此它充满了垃圾。 strlen 将返回垃圾的“长度”,可以是任何东西。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2011-03-15
      • 1970-01-01
      • 1970-01-01
      • 2023-03-17
      • 1970-01-01
      • 1970-01-01
      • 2023-01-01
      • 1970-01-01
      相关资源
      最近更新 更多