对于C中的代码char st[]=“helothere”; printf(“%s”,&st[0]);
,printf如何知道它必须只打印到heloThere,而不是超过heloThere,因为我们只向函数传递第一个字节的地址。 对于C++也要突出显示。 而且这也适用于printf(“%s”,st)
。 因为我们并没有传递上述任何地址。 printf的工作方式有什么不同? 是单独定义的吗? (那么它将是C不支持的重载)
在C和C++中,字符串是以零字符'\0'
结尾的字符序列。
此数组声明
char st[] = "heloThere";
相当于
char st[] = { 'h', 'e', 'l', 'o', 'T', 'h', 'e', 'r', 'e', '\0' };
因此调用printf
printf("%s",&st[0]);
输出表达式&st[0]
指向的字符,直到遇到零字符为止。
此呼叫
printf("%s",st)
等价于上一个调用,因为在极少例外的表达式中使用的数组指定符被转换为指向其第一个元素的指针。
当我们只传递了字符串的字节地址时,printf(“%s”,&st[0])
函数如何知道它需要打印多少内容?
它知道它是因为字符串终止的空字符'\0'
,每个字符串都需要在其末尾提供该字符。
例如,字符串文本“hello”
作为“hello\0”
存储在内存中,该字符串由6
字符组成,而不是由5
字符组成。
请注意,strlen
不计算终止的\0
与,因此它返回5
,而不是6
。
每个char
数组必须至少有一个元素保留给这个终止字符。 否则,如果通过字符串操作函数访问此数组,它将调用未定义的行为。
如果你申报
char st[] = "heloThere";
编译器自动计算所需元素的数量,在本例中是10
,而不是9
。
C或C++编译器在字符串或字符数组的末尾添加'\0'来标记末尾。
char* s = (char*)"Hello!";
这一行实际上看起来像这样的内存
您可能会注意到添加的'\0',这就是printf所做的它循环和计数“”之间的字符,并将这部分内存发送到输出流,printf所做的另一件事是,它返回字符计数器的最终值,但是cout在C++中更复杂,因为它是一个对象而不是函数。
下面代码的执行演示了printf返回计数器值。
cout << printf("%d", printf("%s",s));
执行:你好!61
上面的执行是我们首先打印'hello!‘ 这是由右边的printf完成的,然后我们通过左边的第二个printf打印返回结果,得到6(“hello!”中的字符数) 然后,我们使用cout再次打印第二个printf的返回值,这是一个字符,它是第一个char数组的大小“6”。