5.1.7 指针数组
1、指针和数组的关系
1:指针可以保存数组元素的地址
2:可以定义一个数组,数组中有若干个相同类型指针变量,这个数组被称为指针数组 int *p[5]
指针数组的概念:
指针数组本身是个数组,是个指针数组,是若干个相同类型的指针变量构成的集合
2、指针数组的定义方法:
类型说明符 * 数组名 [元素个数];
int * p[5];//定义了一个整型的指针数组 p,有 5 个元素 p[0]~p[4],
每个元素都是 int *类型的变量
int a;
p[0]=&a;
int b[10];
p[1]=&b[5];
p[2]、*(p+2)是等价的,都是指针数组中的第 2 个元素
例 13: #include <stdio.h> int main(int argc, char *argv[]) { char *name[5] = {"hello","China","beijing","project","Computer"}; int i; for(i=0;i<5;i++) { printf("%s\n",name[i]); } return 0; }
“hello”、“China”“beijing” “project” “computer” 这 5 个字符串存放在文字常量区。
假设:
“hello ”首地址是 0x00002000
“China”首地址是 0x00003000
“beijing”首地址是 0x00004000
“project”首地址是 0x00005000
“Computer”首地址是 0x00006000
则: name[0]中存放内容为 0x00002000
name[1]中存放内容为 0x00003000
name[2]中存放内容为 0x00004000
name[3]中存放内容为 0x00005000
name[4]中存放内容为 0x0000600
注意:name[0] name[1] name[2] name[3] name[4] 分别是 char * 类型的指针变量,分别存放一个地址编号。
3、指针数组的分类
字符指针数组 char *p[10]、短整型指针数组、整型的指针数组、长整型的指针数组
float 型的指针数组、double 型的指针数组 结构体指针数组、函数指针数组
5.1.8 指针的指针
指针的指针,即指针的地址,
咱们定义一个指针变量本身指针变量占 4 个字节,指针变量也有地址编号。
例: int a=0x12345678;
假如:a 的地址是 0x00002000 int *p; p =&a;
则 p 中存放的是 a 的地址编号即 0x00002000 因为 p 也占 4 个自己内存,也有它自己的地址编号,及指针变量的地址,即指针的指针。
假如:指针变量 p 的地址编号是 0x00003000,这个地址编号就是指针的地址 我们定义一个变量存放 p 的地址编号,这个变量就是指针的指针
int **q;
q=&p;//q 保存了 p 的地址,也可以说 q 指向了 p
则 q 里存放的就是 0x00003000
int ***m;
m=&q;
p q m 都是指针变量,都占 4 个字节,都存放地址编号,只不过类型不一样而已
5.1.9 字符串和指针
字符串的概念: 字符串就是以’\0’结尾的若干的字符的集合:比如“helloworld”。
字符串的地址,是第一个字符的地址。
如:字符串“helloworld”的地址,其实是字符串中字符’h’的地址。
我们可以定义一个字符指针变量保存字符串的地址,
比如:char *s =”helloworld”;
字符串的存储形式:
数组、文字常量区、堆
1、 字符串存放在数组中 其实就是在内存(栈、静态全局区)中开辟了一段空间存放字符串。 char string[100] = “I love C!”
定义了一个字符数组 string,用来存放多个字符,并且用”I love C!”给 string 数组初始化 ,字符串“I love C!”存放在 string 中。
注:普通全局数组,内存分配在静态全局区 普通局部数组,内存分配在栈区。 静态数组(静态全局数组、静态局部数组),内存分配在静态全局区
2、 字符串存放在文字常量区 在文字常量区开辟了一段空间存放字符串,将字符串的首地址付给指针变量。
char *str = “I love C!”
定义了一个指针变量 str,只能存放字符地址编号, I love C! 这个字符串中的字符不是存放在 str 指针变量中。 str 只是存放了字符 I 的地址编号,“I love C!”存放在文字常量区
3、 字符串存放在堆区 使用 malloc 等函数在堆区申请空间,将字符串拷贝到堆区。
char *str =(char*)malloc(10);//动态申请了 10 个字节的存储空间,
首地址给 str 赋值。
strcpy(str,"I love C");//将字符串“Ilove C!”拷贝到 str 指向的内存里
字符串的可修改性:
字符串内容是否可以修改,取决于字符串存放在哪里
1. 存放在数组中的字符串的内容是可修改的
char str[100]=”I love C!”;
str[0]=‘y’;//正确可以修改的
注:数组没有用 const 修饰
2. 文字常量区里的内容是不可修改的
char *str=”I love C!”; *str =’y’;//错误,I 存放在文字常量区,不可修改
注: 1、str 指向文字常量区的时候,它指向的内存的内容不可被修改。
2、str 是指针变量可以指向别的地方,即可以给 str 重新赋值,让它指向别的地方。
3. 堆区的内容是可以修改的 char *str =(char*)malloc(10);
strcpy(str,"I love C");
*str=’y’;//正确,可以,因为堆区内容是可修改的
注: 1、str 指向堆区的时候,str 指向的内存内容是可以被修改的。
2、str 是指针变量,也可以指向别的地方。即可以给 str 重新赋值,让它指向别的地方
注意:str 指针指向的内存能不能被修改,要看 str 指向哪里。 str 指向文字常量区的时候,内存里的内容不可修改 str 指向数组(非 const 修饰)、堆区的时候,它指向内存的内容是可以修改
初始化:
1.字符数组初始化: char buf_aver[20]="hello world";
2.指针指向文字常量区,初始化: char *buf_point="hello world";
3、指针指向堆区,堆区存放字符串。 不能初始化,只能先给指针赋值,让指针指向堆区,再使用 strcpy、scanf 等方法把字符串拷贝到堆区。
char *buf_heap;
buf_heap=(char *)malloc(15);
strcpy(buf_heap,"hello world");
scanf(“%s”,buf_heap);
使用时赋值
1. 字符数组:使用 scanf或者 strcpy
char buf[20]=”hello world” buf="hello kitty"; 错误,因为字符数组的名字是个常量,不能用等号给常量赋值。
strcpy(buf,"hello kitty"); 正确,数组中的内容是可以修改的
scanf("%s",buf); 正确,数组中的内容是可以修改的
2. 指针指向文字常量区
char *buf_point = “hello world”;
(1) buf_point="hello kitty"; 正确,buf_point 指向另一个字符串
(2) strcpy(buf_point,"hello kitty"); 错误,这种情况,buf_point 指向的是文字常量区,内容只读。 当指针指向文字常量区的时候,不能通过指针修改文字常量区的内容。
3.指针指向堆区,堆区存放字符串
char *buf_heap; buf_heap=(char *)malloc(15); strcpy(buf_heap,"hello world"); scanf(“%s”,buf_heap);
字符串和指针总结:
1、指针可以指向文字常量区
(1)指针指向的文字常量区的内容不可以修改
(2)指针的指向可以改变,即可以给指针变量重新赋值,指针变量指向别的地方。
2、指针可以指向堆区
(1)指针指向的堆区的内容可以修改。
(2)指针的指向可以改变,即可以给指针变量重新赋值,指针变量指向别的地方。
3、指针也可以指向数组(非 const 修饰)
例: char buf[20]="hello world"; char *str=buf;
这种情况下 1.可以修改 buf 数组的内容。
2.可以通过 str 修改 str 指向的内存的内容,即数组 buf 的内容
3.不能给 buf 赋值 buf=“hello kitty”;错误的。
4.可以给 str 赋值,及 str 指向别处。 str=“hello kitty”