使用带非空终止字符串的printf


107

假设您有一个未null终止的字符串,并且知道其确切大小,那么如何printf在C中打印该字符串?我记得这种方法,但现在不知道...


9
C上下文中,所有字符串均以null结尾。不带null的char数组不是字符串...它们是char数组:)
pmg 2010年


Answers:


174

printf有可能,它像这样:

printf("%.*s", stringLength, pointerToString);

无需复制任何内容,无需修改原始字符串或缓冲区。


10
但是无论如何这很危险,总有一天有人会用%s printf这个字符串
pmod 2010年

6
@Pmod:如果缓冲区未暴露于外界,则不一定。这也是非常有用的,只是打印部分字符串(可能为null终止,当然)。如果您真的希望看到它的实际效果,请查看OpenSER / Kamailio SIP代理,在该代理中,由于该技术很多,他们避免复制内容(也使用sprintf)。
DarkDust

6
另一个+1。当我学习基本事物的东西时,printf甚至是一个十年之后,我
都很

1
对我来说,当我从API接收到一个非空终止的字符串(某些Windows API会这样做!)并必须以“合理”的方式返回它时,它非常有用。因此:%。* s(或%。* S的寿命长,这也将为您转换UNICODE <-> SINGLE-BYTE !;)))
FrizzTheSnail

3
@ user1424739:在您的情况下,printf最多可打印11个字符直到遇到NULL(以先到者为准);在您的示例中,NULL首先出现。指定最大长度不会使NULL失去其“字符串结尾”的含义printf
DarkDust

29

这是有关%.*s工作方式以及在何处指定的说明。

printf模板字符串中的转换规范具有以下一般形式:

% [ param-no $] flags width [ . precision ] type conversion

要么

% [ param-no $] flags width . * [ param-no $] type conversion

第二种形式是从参数列表中获取精度:

您还可以将精度指定为“ *”。这意味着参数列表中的下一个参数(在要打印的实际值之前)将用作精度。该值必须是一个int值,如果为负数则将被忽略。

—  glibc手册中的输出转换语法

对于%s字符串格式,precision具有特殊含义:

可以指定精度以指示要写入的最大字符数;否则,将字符串中的字符(直到但不包括终止空字符)写入输出流。

—  glibc手册中的其他输出转换

其他有用的变体:

  • "%*.*s", maxlen, maxlen, val 将右对齐,并在前面插入空格;
  • "%-*.*s", maxlen, maxlen, val 将左对齐。

如果我理解正确,以下内容将填充输出,但仍防止字符串溢出?"%-*.*s", padding, str_view.size(), str_view.data()
scx

20

您可以使用fwrite()进行标准输出!

fwrite(your_string, sizeof(char), number_of_chars, stdout);

这样,您将第一个字符(在number_of_chars变量中定义的数字)输出到文件,在这种情况下,将输出到stdout(标准输出,您的屏幕)!


2
当您要检查包含字符串和零的长缓冲区时非常有用!
Elist,2013年

13

printf("%.*s", length, string) 不管用。

这意味着要打印最多TO个长度字节或空字节,以先到者为准。如果您的非null终止的char-of-char数组在长度之前包含空字节,则printf将在这些字节上停止,而不会继续。


4
这如何回答OP的问题?
Shahbaz

12
如果它不是以null终止的,则null是要包含的字符串的有效字符。这仍然认为该数组是终止为null的数组,它只是将其视为要从中进行子选择的较长数组-这意味着,如果其中包含带有null的字符串,则将导致问题。
lahwran

3
printf("%.5s", pointerToNonNullTerminatedString);

字符串长度将为5。


1
#include<string.h> 
int main()
{
/*suppose a string str which is not null terminated and n is its length*/
 int i;
 for(i=0;i<n;i++)
 {
 printf("%c",str[i]);
 }
 return 0;
}

我编辑了代码,这是另一种方法:

#include<stdio.h>
int main()
{
printf ("%.5s","fahaduddin");/*if 5 is the number of bytes to be printed and fahaduddin is the string.*/

return 0;

}

由于大量不必要的字节读取(如果字节在大多数CPU上未位于字对齐地址上,这会降低性能),因此性能非常差,而且每个字符都需要进行格式解析和应用。不要那样做:-)请参阅我的答案以获取解决方案。
DarkDust

@DarkDust:只有病理机器会惩罚未对齐字边界的字节读取。您是否认为单词阅读与单词边界不一致?还是一些古老的mi废话?
R .. GitHub停止帮助ICE,2010年

@R ..:如果您认为x86会造成大脑损坏和过时,我绝对同意。因为x86确实会对读写非字对齐的内存造成不利影响。ARM也是如此。参见例如这个问题这个问题。事情是(如果我理解正确的话)是从内存中以字大小的块获取数据,而获取正确的字节是另一个微操作。没什么大不了的,但是在一个巨大的循环中可能会有所作为。
DarkDust 2010年

@DarkDust:关于字节读取,您完全错了。您为什么不去做基准测试?x86具有完全的原子字节操作,并且始终具有。它不会获取字大小的块(高速缓存级别除外,后者会获取更大的块,并且对齐无关紧要,但是我说的是已经缓存的数据)。
R .. GitHub停止帮助ICE,2010年

@ DarkDust:PS3不支持在SPU上读取未对齐的字节。实际上,它甚至不支持标量类型,只有向量必须对齐。编译器模拟它们。而且许多ARM处理器不支持字节读取或写入,而仅执行字读取或写入。
西尔文·德夫雷斯内
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.