指针数组与数组指针
1.指针数组
指针数组可以说成是”指针的数组”,首先这个变量是一个数组,其次,数组的所有元素都是指针类型,在32位系统中,指针占四个字节。
1
2
char* arr[4] = {"hello", "world", "zhejiang", "hangzhou"};
//arr就是我定义的一个指针数组,它有四个元素,每个元素是一个char *类型的指针,这些指针存放着其对应字符串的首地址。
这就相当与定义char *p1 = “hello”,char *p1 = “world”,char *p3 = “zhejiang”, char *p4 = “hangzhou”,这是四个指针,每个指针存放一个字符串首地址,然后用arr[4]这个数组分别存放这四个指针,就形成了指针数组。
2.数组指针
首先定义一个数组指针:
1
char (*ptr)[4];
ptr是一个指针,指向char [4]的数组。注意这个写法,容易误导。
3.示例
1
2
3
4
5
6
7
8
9
10
11
12
13
14
void func() {
// 1.
int arr[4] = {0, 1, 2, 3};
printf("arr: %p\n", arr);
printf("arr_value: %d\n", *arr);
// 2.
int* p1 = arr;
printf("p1: %p\n", p1);
printf("p1_value: %d\n", *p1);
// 3.
int (*p2)[4] = &arr; // 注意这里不能写成int (*p2)[4] = arr
printf("p2: %p\n", p2);
printf("p2_value: %d\n", *p2[0]);
}
输出结果为:
1
2
3
4
5
6
arr: 0x7ffe60abb160
arr_value: 0
p1: 0x7ffe60abb160
p1_value: 0
p2: 0x7ffe60abb160
p2_value: 0
为什么2可以直接赋值,而3需要取址,原因是作为指针,p1与p2指向的对象不同,即指针类型不同,前者指向int类型,后者指向int [4]类型,因此作为数组首地址的arr可以直接赋值给p1,但是需要取地址后赋值给p2
4.字符数组与字符串
正好一并记录一下字符串与数组
4.1 定义
字符数组:元素类型为字符型的数组。
1
char ch[5] = {'a', 'b', 'c', 'd', 'e'};
字符串:用一对双引号括起来的若干个字符序列。
1
char* str = "abcde";
字符串的存储形式与字符数组的存储形式是一样的,除了以下两点区别:
- 字符串本身存储在程序的只读存储区(非常低的一段地址空间)
- 字符串除了所有可见的字符外,末尾还有一个’\0’(ASCII码值为0),作为字符串结束的标志。
4.2 内存图
字符串是存储在数据段的只读数据,只可访问,不可修改,所以像char *str="abcde";
这样定义的字符串又叫做字符串常量。
访问字符串时需要知道字符串的首地址,可以把字符串的首地址保存到一个字符指针里面,这样,就可以通过这个字符指针访问字符串了,如下所示:
1
2
3
4
char *str = "abcde";
printf("%s\n", str); //打印整个字符串常量
printf("%c\n", *str); //打印字符串常量的第一个字符
printf("%c\n", str[1]); //打印字符串常量的第二个字符
字符串常量存储的值不可改变,像下面这样的操作会引起程序崩溃:
1
*(str + 2) = 'g'; //错误,字符串里面的值不可以修改
因为字符串的存储形式与字符数组一致,所以可以用字符串对字符数组进行初始化,如下:
1
2
char ch[] = "abcde";
char ch[] = { "abcde" };
与之等价的写法为:
1
2
char ch[6] = {'a', 'b', 'c', 'd', 'e', '\0'};
char ch[] = {'a', 'b', 'c', 'd', 'e', '\0'};
需要注意的是:
char ch[5] = "abcde";
会报错,越界了,必须为最后一位\0
留一个位置,需要写成char ch[6] = "abcde";
但是写成char ch[5] = {'a', 'b', 'c', 'd', 'e'};
就不会有问题