我想知道printf()函数如何在没有放置终止字符的情况下停止打印字符串。我进行了一个实验,malloc了10个字节的内存,并把恰好10个字符放进去,不知何故,printf函数仍然可以打印这些字符而不会越界,为什么呢?
很有可能在该字符串后面的字符是NULL,因此printf停止输出,此外,在您动态分配的内存之后不为NULL的字符可能不是可打印字符,因此您在终端上看不到它们。
可能是因为你运气不好,所以在你使用malloc
分配的字符串中,下一个字节是0
字节。
你可以通过以下方式进行确认:
const char* digits = "0123456789";
char* buff = (char*)malloc(10);
memcpy(buff, digits, 10);
printf("%s, %d\n", buff, (int)*(buff + 10));
那个0是您没有malloc分配但实际上存在的NULL。 请注意,这种行为是未定义的,因此您不能信任这些事情。正如我之前所说,这是因为您不幸!在这种情况下发生的好事情是SIGSEGV。0123456789 0
strcpy
总是在字符串末尾复制NULL字符。因此,实际上这段代码使用malloc
分配了一个10个字符的buff
,然后将包括NULL在内的11个字符复制到其中。这个操作会导致在内存中紧挨着buff
的任何变量/数据上发生一字节的破坏。 - GrahamS好的,把整个MALLOC的问题放一边,因为对于PRINTF来说,它只是一个字符串,我知道%d、%x、%s等我们用作格式说明符,但事实上printf只是一个"C"函数,可以接受可变数量的参数。
简而言之,printf是一个特殊的函数,将字符串视为传递给它的可变数量CHAR类型参数。
任何\n、\t等参数或%c、%f等都是单个字符,并被视为特殊情况处理。
void myprintf(char * frmt,...)
{
char *p;
int i;
unsigned u;
char *s;
va_list argp;
va_start(argp, fmt);
p=fmt;
for(p=fmt; *p!='\0';p++)
{
if(*p=='%')
{
putchar(*p);continue;
}
p++;
switch(*p)
{
case 'c' : i=va_arg(argp,int);putchar(i);break;
case 'd' : i=va_arg(argp,int);
if(i<0){i=-i;putchar('-');}puts(convert(i,10));break;
case 'o': i=va_arg(argp,unsigned int); puts(convert(i,8));break;
case 's': s=va_arg(argp,char *); puts(s); break;
case 'u': u=va_arg(argp,argp, unsigned int); puts(convert(u,10));break;
case 'x': u=va_arg(argp,argp, unsigned int); puts(convert(u,16));break;
case '%': putchar('%');break;
}
}
va_end(argp);
}
char *convert(unsigned int, int)
{
static char buf[33];
char *ptr;
ptr=&buf[sizeof(buff)-1];
*ptr='\0';
do
{
*--ptr="0123456789abcdef"[num%base];
num/=base;
}while(num!=0);
return(ptr);
}
strcpy
,那么实际上会把11个字符放进去。 - GrahamS