【问题标题】:Apparent oddity in C string initialization: printf and strlen both seem to be in error?C 字符串初始化中的明显奇怪之处:printf 和 strlen 似乎都出错了?
【发布时间】:2021-06-16 17:43:10
【问题描述】:

总体的一般问题是; C 中是否存在一些关于字符串初始化的奇怪之处,似乎没有人评论我可以找到参考/是否有一些特定的 Googlemancy 术语来研究我偶然发现的奇怪之处/是我还是有某种printf 和 strlen 如何处理 C 中的特定字符串的“错误”或“功能”?

我发现虽然 printf 应该打印一个字符串,但它只打印了它的一部分。我发现虽然 strlen 应该报告字符串的长度,但它只报告了其中的一部分。

我是否发现了某种错误,或者这是 C 的一个相当或非常晦涩的“特性”,在这种情况下,这样一个“特性”的细节和讨论术语是什么?

考虑这段代码,以及随后的输出:

代码:

/* Header files for program support */
#include <stdio.h>
#include <string.h>

    /* The primary program section */
int main(void)
{

    /* Variable declaration and initialization*/
    char aitch[30] = "Cat";

    /* What gets done here */
    printf("The string aitch is: %s.\n", aitch);
    printf("strlen says aitch is %lu characters long.\n", strlen(aitch));
    printf("aitch[10] is what is between >> and <<: >>%c<<.\n\n", aitch[10]);

    printf("Now dish out a bunch of chopped liver.\n\n");


    /* More variable declaration and initialization*/
    aitch[11] = ' '; aitch[12] = 'C'; aitch[13] = 'h'; aitch[14] = 'o'; 
    aitch[15] = 'p'; aitch[16] = 'p'; aitch[17] = 'e';  aitch[18] = 'd'; 
    aitch[19] = ' '; aitch[20] = 'l'; aitch[21] = 'i'; aitch[22] = 'v'; 
    aitch[23] = 'e'; aitch[24] = 'r';

    /* Looking over the new stuff */
    printf("aitch listed by character at this point is:\n\n");

    printf("%c", aitch[0]); printf("%c", aitch[1]); 
    printf("%c", aitch[2]); printf("%c", aitch[3]); 
    printf("%c", aitch[4]); printf("%c", aitch[5]); 
    printf("%c", aitch[6]); printf("%c", aitch[7]); 
    printf("%c", aitch[8]); printf("%c", aitch[9]); 
    printf("%c", aitch[10]); printf("%c", aitch[11]); 
    printf("%c", aitch[12]); printf("%c", aitch[13]); 
    printf("%c", aitch[14]); printf("%c", aitch[15]); 
    printf("%c", aitch[16]); printf("%c", aitch[17]); 
    printf("%c", aitch[18]); printf("%c", aitch[19]); 
    printf("%c", aitch[20]); printf("%c", aitch[21]); 
    printf("%c", aitch[22]); printf("%c", aitch[23]); 
    printf("%c", aitch[24]); printf("\n\n");

    /* Hang on, what was that last bit? */
    printf("printf still says all of aitch is %s.\n", aitch);
    printf("strlen still says all of aitch is %lu characters long.\n", 
        strlen(aitch));
    printf("aitch[10] is still what is between >> and <<:  >>%c<<.\n\n", aitch[10]);

    printf("Now put something in the empty area.\n\n");

    /* More variable declaration and initialization*/
    aitch[3] = '_'; aitch[4] = '_'; aitch[5] = '_'; aitch[6] = '_';
    aitch[7] = '_'; aitch[8] = '_'; aitch[9] = '_';  aitch[10] = '_'; 

    /* Ok, _Now_ what??? */
    printf("printf now says all of aitch is:\n\n%s.\n\n", aitch);
    printf("strlen says all of aitch _now_ is %lu characters long.\n", 
        strlen(aitch));
    printf("aitch[10] is now what is between >> and <<:  >>%c<<.\n\n", aitch[10]);

}

输出:

% ./a.out
The string aitch is: Cat.
strlen says aitch is 3 characters long.
aitch[10] is what is between >> and <<: >><<.

Now dish out a bunch of chopped liver.

aitch listed by character at this point is:

Cat Chopped liver

printf still says all of aitch is Cat.
strlen still says all of aitch is 3 characters long.
aitch[10] is still what is between >> and <<:  >><<.

Now put something in the empty area.

printf now says all of aitch is:

Cat________ Chopped liver.

strlen says all of aitch _now_ is 25 characters long.
aitch[10] is now what is between >> and <<:  >>_<<.

【问题讨论】:

  • 我会选择“晦涩的功能”。你知道什么是字符串,用C语言吗?
  • 请告诉我们你对C中的字符串的理解。这显然是一个错误的理解。 C 字符串在第一个 NUL 字符处结束。您的“切碎的肝脏”代码写入 NUL 字符之后的字符,因此它当然不会更改原始字符串。 printfstrlen 都没有错。
  • 您应该提及您期望发生的事情。并重新审视字符串是什么。简而言之:如果它没有被 strlen 计算或被 printf("%s") 打印,那么它不是该字符串的一部分。它可能是另一个字符串的一部分或根本没有字符串。
  • OT:25 printf("%c", aitch[x]) 可以替换为 for 循环,该循环的编写速度比复制/粘贴并将 x 替换为 0..25 更快
  • 在第一部分,aitch[3] 仍然包含一个 nul 字符串终止符,因此 strlen() 报告相同的长度,printf() 输出相同的字符串。 strlen()printf() 都没有损坏。

标签: c string initialization printf strlen


【解决方案1】:

在C语言中,字符串是:一系列字符,以空字符(一个0字节)结尾。

char aitch[30] = "Cat";

这声明了一个 30 个字符的数组。第一个是'C',第二个是'a',第三个是't',第四个是null(结束字符串),其余都是null(默认)。 (注意:char aitch[30]; 本身不会使它们全部为空)

所以你有 30 个字符的空间。如果您使用从第一个字符开始的空格,则该空格中存储了一个有效的字符串:'C'、'a'、't'、0。这是一个长度为 3 个字符的字符串。如果您调用strlen,它将返回 3,因为这是字符串的长度。如果你打印它,它会打印 3 个字符,因为那是字符串的长度。

请注意,30 个字符的 空格 与 30 个字符的字符串不同。空间是空间,字符串是您实际存储在那里的数据。您有 26 个字符不是字符串的一部分,如果需要,您可以使用它们。

事实上,你有足够的空间来存储两个不同的字符串!这正是您在代码中所做的。

如果你确保它们之间没有空字节,它们又会变成一个字符串。

请注意,字符串的任何“结尾部分”也是有效字符串。如果从数组中的位置 0 开始,则会得到字符串“Cat”。但是如果你从位置 1 开始你得到“at”,如果你从位置 2 开始你得到“t”,如果你从位置 3 开始你得到“”。一切都很好用。

【讨论】:

    【解决方案2】:
    char aitch[30] = "Cat";
    

    这里,aitch 中的前 4 个chars 将依次为:Cat\0\0 是空终止符。 C 中的字符串以空值结尾。像 printfstrlen 这样的函数需要一个 NULL 终止的字符串,一旦遇到一个空终止符就会停止处理该字符串。

    当您直接写入 aitch[3] 时,您会覆盖该空终止符。

    【讨论】:

    • 在 C 中,NULL 是一个用于空指针常量的宏。值为零的字符只是一个空字符;它不是 NULL。
    【解决方案3】:

    我们这里是沟通失败---你们的评论和回答都很好,回答评论非常感谢。

    问题,正如其他地方可能也看到的那样,是对 C 的超现实的可怕评论,在那边,在那边,等等,如果不梳理就无法判断任何东西的质量通过各种各样的,无论人们在哪里找到它,并通过编写演示代码来测试一切

    在这种情况下,一个非常特殊的例子是相当多的书籍 cmets、在线 cmets 等,它们声明 char aitch[30] 本质上是创建一个 30 个字符长的字符串,然后在这里初始化并那里 。 . . 据此,无论是一组字符还是两个或多个分开的字符都无关紧要,都是一个字符串。

    基于“C”中“字符串”的定义,那么是的,printf 尤其是 strlen 的行为不正确。

    就我而言,我确实在对 C 进行自动驾驶研究和深入挖掘,并且不得不浏览许多此类非常垃圾的文档实例。因此,出于自卫考虑,我正在编写自己的笔记,并附有明确功能的示例代码块来支持所有内容。

    ---对于可以在示例代码中放入循环的评论,基本上是的,但学究起来,还没有---我正在做的笔记目前正在从函数开始后梳理变量,并且循环将持续一两章。

    这个实例不会是我在学习过程中遇到的最后一个评论混乱。---不,我不知道下一个混乱会是什么,我只知道会有成为一个,然后是下一个,然后是下一个。 . . .

    【讨论】:

      猜你喜欢
      • 2014-08-26
      • 1970-01-01
      • 2020-08-01
      • 2010-12-01
      • 2011-02-22
      • 1970-01-01
      • 2011-08-18
      • 1970-01-01
      相关资源
      最近更新 更多