C语言 字符指针和 printf 函数
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/40002185/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Char pointers and the printf function
提问by Fabulous
I was trying to learn pointers and I wrote the following code to print the value of the pointer:
我试图学习指针,并编写了以下代码来打印指针的值:
#include <stdio.h>
int main(void) {
char *p = "abc";
printf("%c",*p);
return 0;
}
The output is:
输出是:
a
一种
however, if I change the above code to:
但是,如果我将上面的代码更改为:
#include <stdio.h>
int main(void) {
char *p = "abc";
printf(p);
return 0;
}
I get the output:
我得到输出:
abc
美国广播公司
I don't understand the following 2 things:
我不明白以下两件事:
why did printf not require a format specifier in the second case? Is
printf(pointer_name)enough to print the value of the pointer?as per my understanding (which is very little), *p points to a contiguous block of memory that contains
abc. I expected both outputs to be the same, i.e.
为什么 printf 在第二种情况下不需要格式说明符?是
printf(pointer_name)足以打印指针的值?根据我的理解(非常少), *p 指向包含
abc. 我希望两个输出相同,即
abc
美国广播公司
are the different outputs because of the different ways of printing?
不同的输出是因为打印方式不同吗?
Edit 1
编辑 1
Additionally, the following code produces a runtime error. Why so?
此外,以下代码会产生运行时错误。为什么这样?
#include <stdio.h>
int main(void) {
char *p = "abc";
printf(*p);
return 0;
}
回答by Some programmer dude
For your first question, the printffunction (and family)takes a string as first argument (i.e. a const char *). That string could contain format codes that the printffunction will replace with the corresponding argument. The rest of the text is printed as-is, verbatim. And that's what is happening when you pass pas the first argument.
对于您的第一个问题,printf函数(和系列)将字符串作为第一个参数(即 a const char *)。该字符串可能包含printf函数将用相应参数替换的格式代码。文本的其余部分按原样逐字打印。这就是当你p作为第一个参数传递时发生的事情。
Do note that using printfthis way is highly unrecommended, especially if the string is contains input from a user. If the user adds formatting codes in the string, and you don't provide the correct arguments then you will have undefined behavior. It could even lead to security holes.
请注意,printf强烈不推荐使用这种方式,尤其是当字符串包含来自用户的输入时。如果用户在字符串中添加格式代码,而您没有提供正确的参数,那么您将有未定义的行为。它甚至可能导致安全漏洞。
For your second question, the variable ppoints to some memory. The expression *pdereferences the pointer to give you a single character, namely the one that pis actually pointing to, which is p[0].
对于您的第二个问题,该变量p指向一些内存。该表达式*p取消引用指针以给您一个字符,即p实际指向的字符,即p[0].
Think of plike this:
p像这样想:
+---+ +-----+-----+-----+------+ | p | ---> | 'a' | 'b' | 'c' | '' | +---+ +-----+-----+-----+------+char *p = "abc"; printf(p);
The variable pdoesn't really point to a "string", it only points to some single location in memory, namely the first character in the string "abc". It's the functions using pthat treat that memory as a sequence of characters.
该变量p并不真正指向“字符串”,它仅指向内存中的某个位置,即 string 中的第一个字符"abc"。它是使用p将内存视为字符序列的函数。
Furthermore, constant string literals are actually stored as (read-only) arrays of the number of character in the string plus one for the string terminator.
此外,常量字符串文字实际上存储为字符串中字符数加上字符串终止符一的(只读)数组。
Also, to help you understand why *pis the same as p[0]you need to know that for any pointer or arraypand valid index i, the expressions p[i]is equal to *(p + i). To get the first character, you have index 0, which means you have p[0]which then should be equal to *(p + 0). Adding zero to anything is a no-op, so *(p + 0)is the same as *(p)which is the same as *p. Therefore p[0]is equal to *p.
此外,为了帮助您理解为什么*p与p[0]您需要知道的相同,对于任何指针或数组p和有效索引i,表达式p[i]等于*(p + i)。要获得第一个字符,您有 index 0,这意味着您拥有p[0]which 那么应该等于*(p + 0)。向任何内容添加零是无操作的,因此*(p + 0)与*(p)which 与*p. 因此p[0]等于*p。
Regarding your edit (where you do printf(*p)), since *preturns the value of the first "element" pointed to by p(i.e. p[0]) you are passing a single characteras the pointer to the format string. This will lead the compiler to convert it to a pointer which is pointing to whatever address has the value of that single character (it doesn't convert the character to a pointer tothe character). This address is not a very valid address (in the ASCII alphabet'a'has the value 97which is the address where the program will look for the string to print) and you will have undefined behavior.
关于你的编辑(你在哪里做printf(*p)),因为*p返回p(即p[0])指向的第一个“元素”的值,你传递了一个字符作为指向格式字符串的指针。这将导致编译器将其转换成其指向任何地址都有单个字符值的指针(它不字符转换为指针,以字符)。这个地址不是一个非常有效的地址(在ASCII 字母表'a'中的值97是程序将在其中查找要打印的字符串的地址)并且您将有未定义的行为。
回答by Oskar Skog
pis the format string.print("abc");is the same as
char *p = "abc"; printf(p); /* If p is untrusted, bad things will happen, otherwise the string p is written. */ printf("%c", *p); /* print the first byte in the string p */ printf("%s", p); /* print the string p */Doing this is very bad practice because you don't know what the variable will contain, and if it contains format specifiers, calling
printfmay do very bad things.The reason why the first case (with
"%c") only printed the first character is that%cmeans a byte and*pmeans the (first) value whichpis pointing at.%swould print the entire string.char *p = "abc"; printf(p);
p是格式字符串。print("abc");是相同的
char *p = "abc"; printf(p); /* If p is untrusted, bad things will happen, otherwise the string p is written. */ printf("%c", *p); /* print the first byte in the string p */ printf("%s", p); /* print the string p */这样做是非常糟糕的做法,因为您不知道变量将包含什么,并且如果它包含格式说明符,调用
printf可能会做非常糟糕的事情。第一个 case (with
"%c") 只打印第一个字符的原因是这%c意味着一个字节并且*p意味着p指向的(第一个)值。%s将打印整个字符串。char *p = "Hello";
回答by giorgim
You are misunderstanding, indeed when you do
你误会了,确实当你这样做的时候
*p
ppoints to the starting address where literal "Hello" is stored. This is how you declarepointers. However, when afterwards, you do
p指向存储文字“Hello”的起始地址。这就是您声明指针的方式。但是,当之后,你做
printf("Hello");
it means dereferencepand obtain object where ppoints. In our above example this would yield 'H'. This should clarify your second question.
这意味着取消引用p并获得p指向的对象。在我们上面的例子中,这将产生“H”。这应该澄清你的第二个问题。
In case of printf just try
在 printf 的情况下,请尝试
printf(*p);
which is also fine; this answers your first question because it is effectively the same what you did when passed just pto printf.
这也很好;这回答了您的第一个问题,因为它实际上与仅传递p给 printf时所做的相同。
Finally to your edit, indeed
终于到你的编辑了,确实
printf("abc"); // Perfectly fine!
above line is not correct since printf expects const char *and by using *pyou are passing it a char- or in other words 'H' assuming our example. Read more what dereferencing means.
上面的行是不正确的,因为 printf 期望const char *并且通过使用*p你正在传递它char- 或者换句话说 'H' 假设我们的例子。阅读更多取消引用的含义。
回答by QuestionC
- why did printf not require a format specifier in the second case? Is printf(pointer_name) enough to print the value of the pointer?
- 为什么 printf 在第二种情况下不需要格式说明符?printf(pointer_name) 足以打印指针的值吗?
"abc" isyour format specifier. That's why it's printing "abc". If the string had contained %, then things would have behaved strangely, but they didn't.
“abc”是您的格式说明符。这就是它打印“abc”的原因。如果字符串包含%,那么事情的表现会很奇怪,但事实并非如此。
printf ("%s", p);
- why did printf not require a format specifier in the second case? Is printf(pointer_name) enough to print the value of the pointer?
- 为什么 printf 在第二种情况下不需要格式说明符?printf(pointer_name) 足以打印指针的值吗?
%cis the character conversion specifier. It instructs printfto only print the first byte. If you want it to print the string, use...
%c是字符转换说明符。它指示printf只打印第一个字节。如果您希望它打印字符串,请使用...
The %sseems redundant, but it can be useful for printing control characters or if you use width specifiers.
这%s似乎是多余的,但它对于打印控制字符或使用宽度说明符很有用。
The best way to understand this really is to try and print the string abc%defusing printf.
真正理解这一点的最好方法是尝试abc%def使用printf.
回答by Lundin
why did printf not require a format specifier in the second case? Is printf(pointer_name) enough to print the value of the pointer?
为什么 printf 在第二种情况下不需要格式说明符?printf(pointer_name) 足以打印指针的值吗?
With your code you told printf to use your string as the format string. Meaning your code turned equivalent to printf("abc").
使用您的代码,您告诉 printf 使用您的字符串作为格式字符串。这意味着您的代码变成等效于printf("abc").
as per my understanding (which is very little), *p points to a contiguous block of memory that contains abc. I expected both outputs to be the same
根据我的理解(非常少),*p 指向包含 abc 的连续内存块。我希望两个输出相同
If you use %cyou get a character printed, if you use %syou get a whole string. But if you tell printf to use the string as the format string, then it will do that too.
如果你使用%c你会打印一个字符,如果你使用%s你会得到一个完整的字符串。但是如果你告诉 printf 使用字符串作为格式字符串,那么它也会这样做。
char *p = "abc";
printf(*p);
char *p = "abc";
printf(*p);
This code crashes because the contents of p, the character 'a'is not a pointer to a format string, it is not even a pointer. That code should not even compile without warnings.
这段代码崩溃是因为p, 字符的内容'a'不是指向格式字符串的指针,它甚至不是指针。该代码甚至不应该在没有警告的情况下编译。
回答by Bathsheba
The %cformat specifier expects a chartype, and will output a singlecharvalue.
的%c格式说明需要一个char类型,并且将输出一单个char数值。
The first parameter to printfmust be a const char*(a char*can convert implicitly to a const char*) and points to the startof a stringof characters. It stops printing when it encounters a \0in that string. If there is not a \0present in that string then the behaviour of that function is undefined. Because "abc"doesn't contain any format specifiers, you don't pass any additional arguments to printfin that case.
第一个参数printf必须是一个const char*(一个char*可以隐式转换为const char*),并指向启动一个的字符串的字符。当遇到\0该字符串中的a 时,它会停止打印。如果\0该字符串中不存在,则该函数的行为是undefined。因为"abc"不包含任何格式说明符,所以printf在这种情况下您不会传递任何其他参数。

