0%

Character Array and Character Pointer

最近复习数据结构实验时,碰到这么一行代码,看的有点不爽。

1
typedef char** HuffmanCode;

借此梳理下数组和指针。

1
int* p; //指针变量p中存的地址代表的内存单元中的数据是整型

在32位平台下,由于p存的是地址,故p的值是32位。
不论p指向什么类型的数据,指针变量p本身都是整型。

c中没有string类型,所以一般用字符数组表示字符串。

1
char str[15] = "Hello World";

c规定数组名表示数组在内存中的首地址,就是str = &str[0],我们一般输出字符串时printf("%s",str);,首地址就可以输出整个字符串。

在c中可以这么干:

1
2
char *s;
s = "Hello";

一个字符串赋值给一个指针变量??

事实上,c的编译器会给字符串常量分配内存,假设"Hello"的地址是0x0000000000404000 0x0000000000404001 0x0000000000404002 0x0000000000404003 0x0000000000404004 0x0000000000404005,(我是64位环境)
其实是s = "Hello" = 0x0000000000404000,c编译器把这个串看作首地址。

做个测试:

1
2
3
printf("%s\n",s);
printf("%s\n",0x0000000000404000);
这两行的效果是一样的。
1
2
char str[10];
char* s;

str表示首地址,s也保存首地址,所以可以这样:

1
2
s = str;
但是不可以 str = s;

因为数组名是一个常量,不能被赋值。
事实上,char str[10]编译器会分配10个内存单元,而char* s只是定义了一个指针变量,32位环境下只分配4个字节,用来保存字符串首地址。

不信测试下:

1
2
sizeof(str) = 10;
sizeof(s) = 4; //分配四个字节来保存地址

所以数组名和指针变量本质上是不同的。

接下来我们看看char**与char* a[]
对于char* a[],a实质上还是一个数组,这个数组保存的元素是char*类型的,char*也就是存着地址的变量。

所以可以这样:

1
char* a[] = {"me","you","him"};

这时在32位环境下sizeof(a) = 12,因为a中的3个元素都是char*指针,而指针变量占4个字节。
可以打印出来看看:

1
2
printf("%p %p %p\n",a[0],a[1],a[2]);
printf("%p %p %p\n",&a[0],&a[1],&a[2]);

在这里插入图片描述
数组中3个元素保存了3个地址,也就是3个字符串的首地址。

对于char** s
二级指针变量s保存一级指针char*的地址,我们可以:

1
s = a;

数组名a=&a[0]=62FE30,而这个地址中(即a[0])保存的是404000这个地址,也就是字符串"me"的首地址,即:

1
*s = 404000 = "me";

易错点1:

1
char** s = "Hello";
这是错的,因为s是char** ,而"Hello"是char*
虽然都是地址,但是"Hello"表示的地址中内容是H,char型; s存的地址中的内容(*s)是char*型,指针类型。

易错点2:

1
2
char** s;
*s = "Hello";
这样编译不会错,但是运行时printf("%s",*s);就会崩溃。

假设s=0x1000,在0x1000内存单元中存的是"Hello"的地址0x2000,即*s = 0x2000,这样执行时先找到0x1000,然后是0x2000,没有问题。

char** s;,s存的是一个随机的地址,也就是野指针,*s就可能会崩溃。

所以要先分配一个地址:

1
2
3
char** s;
s = (char**) malloc(sizeof(char**));
*s = "Hello";

这样s就有了可用的地址。

参考: https://blog.csdn.net/liusicheng2008_liu/article/details/80412586