*s[]
,我可以做到以下几点:char *s[] = {"foo", "bar", "foobar", "whatever", "john", "doe"};
char **s
和char *s[]
有什么不同?在这种情况下,我如何使用char **s
而不是char *s[]
?
例如:int main(int argc, char **argv)
而不是*argv[]
*s[]
,我可以做到以下几点:char *s[] = {"foo", "bar", "foobar", "whatever", "john", "doe"};
char **s
和char *s[]
有什么不同?在这种情况下,我如何使用char **s
而不是char *s[]
?
例如:int main(int argc, char **argv)
而不是*argv[]
对于函数参数,没有任何区别。
否则:
char *s[];
s是一个指向char类型的指针数组。
char **s;
s是指向指向字符的指针。
如果您需要一个指向字符指针的数组,则使用前者;如果您需要一个指向指向字符的指针的指针,则使用后者。
void f(int** p);
void f(int* p[]);
void f(int* p[42]);
char *s[] = {"foo", "bar", "foobar", "whatever", "john, "doe"};
s
是一个指向 char
类型的指针数组,包含 6
个指针。 sizeof(s) == 6*sizeof(void*)
char **s;
s
是指向指针的指针,sizeof(s) == sizeof(void*)
sizeof(char *)
而不是 void *
。 - tomlogicvoid*
来强调所有指针具有相同的大小,并且一个是指针,另一个是指针数组(无论指向什么)。 - Armen Tsirunyan和
void *`具有相同的大小和表示形式。 - Alok Singhal数组和指针是不同的东西。指针可以用来访问数组中的元素。要初始化一个数组,你需要声明一个数组,而不是一个指针。
为了清楚地展示这种差异,请尝试以下操作:
int[] ia = {1, 2, 3, 4, 5, 6, 7, 8};
int* ip = ia;
printf("sizeof(ia): %zu, sizeof(ip): %zu", sizeof(ia), sizeof(ip));
第一个应该打印数组的大小,第二个应该打印 int 指针的大小。
C 语言中奇怪的是,当数组作为参数传递给函数时,它会转换成指针。详见 http://www.lysator.liu.se/c/c-faq/c-2.html 第 2.3 节。主函数接受 argv**
而不是 argv*[]
的原因是当作为函数参数传递时,argv*[]
会转换成 argv**
。
这不是直接回答你的问题,但可能会帮助你更好地理解:
#include <stdio.h>
#include <string.h>
int main() {
char *s[] = {"foo", "bar", "foobar", "whatever", "john", "doe"};
printf(" s[0]: %s \n", s[0]);
printf(" *s: %s \n", *s);
printf(" *s+1: %s \n", *s+1);
printf("*(s+1): %s \n", *(s+1));
return 0;
}
输出:
$ gcc -o chararr chararr.c
$ ./chararr
s[0]: foo
*s: foo
*s+1: oo
*(s+1): bar
它们创建相同的数据结构。唯一的区别是char*s[]在初始化时自动为{"foo", "bar", "foobar", "whatever", "john, "doe"}
分配足够的内存。而char **s只会为指针分配一个字节,然后您需要手动为数组中的每个字符串分配内存。
如果你定义了
char **s[] = {"foo", "bar", "foobar", "whatever", "john, "doe"};
我认为这与定义三维数组(char s[10][10][10])相同,因为char *s[]定义了一个二维数组。
这取决于您的需求。如果您的程序不需要稍后修改这些字符串,您可以使用
char *s[] = {"foo", "bar", "foobar", "whatever", "john", "doe"};
这些被编译为只读区域中的字符串字面量。
汇编输出:
.file "test.c"
.section .rodata
.LC0:
.string "foo"
.LC1:
.string "bar"
.LC2:
.string "foobar"
.LC3:
.string "whatever"
.LC4:
.string "john"
.LC5:
.string "doe"
.text
如果您尝试在程序中稍后修改这些字符串,您将会得到一个分段错误。在这种情况下,您必须使用char **s
。
char *s[] = {"foo", "bar", "foobar", "whatever", "john, "doe"};
时,编译器已经知道数组的长度,即在这种情况下,它知道它是指向6个字符数组的指针。
char **
缺乏长度信息,这正是为什么main有2个参数{length, pointer to pointer to char} == {argc, arv}
的原因。