C语言 字符串被垃圾填满

s4n0splo  于 2022-12-03  发布在  其他
关注(0)|答案(3)|浏览(172)

我得到了一个字符串和一个scanf,它从input中读取,直到找到一个 *,这是我选择的文本结尾字符。在 * 之后,所有剩余的单元格都将被随机字符填充。我知道,\0字符之后的字符串如果直到最后一个单元格才被完全填充,则将用\0填充所有剩余的空单元格。为什么不是这种情况,我怎样才能使在input中给出的最后一个字母之后,所有剩余的单元格都是相同的值?

char string1 [100];

    scanf("%[^*]s", string1);
    for (int i = 0; i < 100; ++i) {
        printf("\n %d=%d",i,string1[i]);
}

如果我尝试输入hello* 之类的内容,输出如下:

0=104   
 1=101   
 2=108   
 3=108   
 4=111   
 5=0
 6=0
 7=0
 8=92
 9=0
 10=68
u0njafvf

u0njafvf1#

您有一个未初始化的数组:

char string1 [100];

的数组。您可以将数组初始化为

char string1 [100] = { 0 };

char string1 [100] = "";

在这通电话中

scanf("%[^*]s", string1);

您需要删除尾随字符s,因为%[]%s是不同的格式说明符。没有%[]s说明符。它应该如下所示:

scanf("%[^*]", string1);

数组包含以零字符'\0'结尾的字串。
因此,要输出字符串,您应该编写例如

for ( int i = 0; string1[i] != '\0'; ++i) {
    printf( "%c", string1[i] ); // or putchar( string1[i] );
putchar( '\n' );

或类似

for ( int i = 0; string1[i] != '\0'; ++i) {
    printf("\n %d=%c",i,string1[i]);
putchar( '\n' );

或仅

puts( string1 );

至于你的陈述

printf("\n %d=%d",i,string1[i]);

然后,由于使用转换说明符d而不是c,它将每个字符(包括未初始化的字符)作为整数输出。也就是说,该函数输出字符的内部ASCII表示形式。

5f0d552i

5f0d552i2#

我知道\0字符后面的字符串如果直到最后一个单元格才完全填充,则会用\0填充所有剩余的空单元格
不,那不是真的。这不可能是真的:字符串没有长度。编译器和任何函数都不知道字符串的长度。只有你知道。所以,不,字符串不会自动填充'\0'
请记住,C语言中没有任何字符串类型,只有指向字符的指针(有时这些指针是指向数组的常量指针,但它们仍然只是指针。我们知道它们从哪里开始,但没有办法(除了在编码时确定它并保持一致)知道它们在哪里结束。
当然,大多数情况下,有一个显而易见的答案,它使任何代码读者都清楚所分配内存的大小。
例如,当您编写

char string1[20];
sprintf(string1, "hello");

对于代码的读者来说,分配的内存是20个字节是显而易见的。因此,你可能认为编译器应该知道,当在它里面进行扫描时,它应该用0填充20个字节中未使用的部分。但是,首先,当你进行sscanf或sprintf时,编译器已经不在那里了。这发生在运行时,编译器在编译时。在运行时,没有20踪迹。
另外,事情可能比这更复杂

void fillString(char *p){
    sprintf(p, "hello");
}

int main(){
    char string1[20];
    string1[0]='O';
    string1[1]='t';
    fillString(&(string1[2]));
}

在这种情况下,sprintf应该如何知道它必须用字符串填充18个字节,然后是'\0'?
这是正常的用法,我还没有开始使用复杂但法律的的用法,比如使用char buffer[1000];作为50个长度为20的字符串的数组(bufferbuffer+20buffer+40,...),或者类似的东西

union {
    char str[40];
    struct {
        char substr1[20];
        char substr2[20];
    } s;
}

所以,不,字符串不是用'\0'填充的。事实并非如此。C语言中没有让隐含的东西在引擎盖下发生的习惯。即使我们想,也不可能是这样的。
你的“以星号结尾的字符串”的行为和“以空值结尾的字符串”的行为完全一样。有时分配的内存的剩余部分充满了0,有时没有。scanf不会接触任何其他严格需要的东西。分配的内存的剩余部分保持不变。如果在调用scanf之前,该内存碰巧充满了'\0',那么它就保持不变,否则就不是。这就引出我的最后一句话:您似乎相信是scanf用非空字符填充内存。但事实并非如此。这些字符以前就已经存在。如果您觉得其他方法用'\0'填充了内存的其余部分,那只是一种印象(这是很自然的,因为大多数时候,新分配的内存是0。不是因为规则这么说。而是因为这是在内存的随机区域中最频繁出现的字节。这就是为什么未初始化的变量错误是如此痛苦:它们只是偶尔出现,因为未初始化的变量经常是0,这只是偶然的,但它们仍然是0)

n1bvdmb6

n1bvdmb63#

创建一个置零数组最简单的方法是使用calloc。使用char * 字符串1 =calloc(1,100);

相关问题