#include <stdio.h>
// this works
void print_stuff (void* buf) {
printf ("passed arg as buf*: %s\n", buf);
}
/* This works */
void print_stuff_3 (char* buf) {
printf ("passed arg as char*: %s\n", buf);
}
// this does not work
void print_stuff_2 (char** buf) {
printf ("%s\n", *buf);
}
int main () {
char s [] = "hi";
printf ("s = %s\n", s);
// these work
print_stuff (&s);
print_stuff_3 (&s);
// this results in a Segfault
print_stuff_2(&s);
return 0;
}
我对C中传递内容的方式感到有点困惑。我觉得&s
应该是char**
类型,但它的行为就像char*
类型一样传递给函数时。为什么会出现这种情况?
特别是print_stuff_2
段错误,而我认为print_stuff_3
会出错。
编辑:澄清一下,我希望print_stuff(&s)
和print_stuff_3(&s)
失败(虽然他们成功了),而print_stuff_2(&s)
失败,而我觉得它应该成功。
答案 0 :(得分:3)
你需要记住字符串不是C中的基本类型。它们是字符数组。因此
char s [] = "hi";
使s
成为char *
(就变量类型而言),即指向3个字符数组的第一个字符的指针(h
,i
和{{ 1}})。
因此,为了传递指向字符串的指针,您使用NUL
的内容,因为print_stuff_3
的{{1}}参数正是如此(指向string,即指向第一个字符的指针。请使用printf()
。
%s
有效,因为指针是一个指针。它会在调用print_stuff_3(s)
后转换为print_stuff
指针,然后void *
print_stuff
会将其转换回printf()
。请使用%s
。
char *
无法正常工作,因为您正在获取存储print_stuff(s)
的地址。如果您使用print_stuff_2
,那么您写的s
是否可行。您将传递指针的地址,然后使用char *s = "hi";
取消引用(以获取指针的值,即指向第一个字符的指针)。除了print_stuff_2(&s)
之外,那么名称将是一个糟糕的选择,因为你将指向一个指向字符的指针。
复杂情况如下。实际上,您正在执行*buf
,只有在您拥有
buf
&s
(参见How come an array's address is equal to its value in C?),但如果您有以下内容,则返回指针变量s
存储在堆栈中的地址:
char s [] = "hi";
获取数组的地址并不真正有意义(因此计算第一个元素的地址)。如果要获取指针的地址,则需要使用s
。
答案 1 :(得分:0)
在C中,在大多数情况下,数组名称在传递给函数时会衰减指向其第一个元素。将s
传递给函数print_stuff
时,s
会衰减指针h
。无需通过&
传递它。 &s
是指向数组(char (*)[3]
)类型的指针,即它给出整个数组s
的地址。
在函数调用中
print_stuff_3 (&s);
你的编译器应警告你
[Warning] passing argument 1 of 'print_stuff_3' from incompatible pointer type [enabled by default]
我觉得
&s
应该是char*
*类型,但是当它传递给函数时,它的行为就好像它是char*
类型一样。为什么会出现这种情况?
没有。你错了。 &amp; s属于char (*)[3]
类型。
答案 2 :(得分:0)
void print_stuff (void* buf)
&amp; void print_stuff_3 (char* buf)
在这两个函数中,buf
都是char *
以地址为参数。哪个应该是print_stuff (s)
&amp; print_stuff_3 (s)
分别为s
是char数组s
的基址。因此,您不应该传递&s
s
的地址。
由于以下函数buf
属于char **
类型,如果您的声明为print_stuff_2(&s)
,则会预期地址为char *s = "hi"
,
void print_stuff_2 (char** buf) {
printf ("%s\n", *buf);
}