C语言进阶4——指针的进阶
Posted 初学C语言者
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了C语言进阶4——指针的进阶相关的知识,希望对你有一定的参考价值。
指针的进阶(1)
前言
本文开始学习指针进阶相关的知识点了。前面已经在初识C语言、C语言基础阶段学习过了指针的内容了:
在基础阶段初步知道了指针的概念:
- 指针就是个变量,用来存放地址,地址唯一标识一块内存空间
- 指针的大小是固定的4/8个字节(32位平台/64位平台)
- 指针是有类型,指针的类型决定了指针的±整数的步长,指针解引用操作的时候的权限
- 指针的运算
在进阶阶段将会按照下面顺序,更加深入地依次学习指针的相关内容:
- 字符指针
- 数组指针
- 指针数组
- 数组传参和指针传参
- 函数指针
- 函数指针数组
- 指向函数指针数组的指针
- 回调函数
- 指针和数组面试题的解析
1、字符指针
指针类型为字符指针 char*
int main()
char ch = 'w';
char *pc = &ch;//字符指针
*pc = 'a';
printf("%c\\n", ch);
代码是将字符串的abcdef的首字符的地址存放指针pa里了
用const限制指针pa,即常量指针:
指针指向的地址里存放的内容,*pa 不能修改,
指针指向的地址,pa,可以修改
const char* pa = "abcdef";
//*pa = 'a';//错误的,const限制后,不能修改
printf("%c\\n", *pa);
printf("%s\\n", *pa);
return 0;
通过调试看到常量字符串是将其首字符 ‘a’ 的地址赋值给指针 *pa :
int main()
char ch1[] = "hello world";//字符串一般用数组定义
char ch2[] = "hello world";
const char* p1 = "hello world";//指针变量接受字符串地址
const char* p2 = "hello world";
if (ch1 == ch2)
printf("ch1 and ch2 are same\\n");
else
printf("ch1 and ch2 are not same\\n");
if (p1 == p2)
printf("p1 and p2 are same\\n");
else
printf("p1 and p2 are not same\\n");
return 0;
- 这里p1和p2指向的是同一个常量字符串
- C/C++会把常量字符串存储到单独的内存中的常量区域
- 当几个指针指向同一个字符串的时候,他们实际会指向同一块内存
- 用相同的常量字符串,去初始化不同的数组的时候就会开辟出不同的内存块,ch1和ch2不同
2、指针数组
指针数组:指针数组就是一个数组,数组里每个元素都是指针,即是地址
前面关于数组,我们学过了几种类型的数组:
整型数组
int arr[10];存放整型的数组,数组里的每个元素都是int类型
字符数组
char arr2[10];存放字符的数组,数组里的每个元素都是char类型
指针数组
int* arr[10];存放指针的数组,数组里的每个元素都是int*类型,即指针,也是地址
2.1 在一维数组中使用
int main()
int a = 10;
int b = 20;
int c = 30;
int* p1 = &a;
int* p2 = &b;
int* p3 = &c;
int* arr[3] = &a,&b,&c ;//指针数组,数组的元素都是地址,也就是指针
for (int i = 0; i < 3; i++)
//arr[i]每个元数都是地址,对地址解引用就是取a、b、c的值
printf("%d ", *(arr[i]));
return 0;
调试结果见下图:
2.2 在二维数组中使用
int main()
int arr1[5] = 1,2,3,4,5 ;
int arr2[5] = 2,3,4,5,6 ;
int arr3[5] = 3,4,5,6,7 ;
int* parr[3] = arr1,arr2,arr3 ;//指针数组,数组元素都是地址
for (int i = 0; i < 3; i++)
for (int j = 0; j < 5; j++)
printf("%d ", parr[i][j]);//parr[0]=arr1
printf("\\n");
printf("\\n");
for (int i = 0; i < 3; i++)
for (int j = 0; j < 5; j++)
printf("%d ", *(parr[i] + j)); //
printf("\\n");
printf("\\n");
for (int i = 0; i < 3; i++)
for (int j = 0; j < 5; j++)
printf("%d ", *(*(parr + i) + j));//*(parr + i) = parr[i]
printf("\\n");
return 0;
)
调试结果见下图:
3、数组指针
3.1 数组指针的定义
数组指针是指针,这个指针指向数组,即指针存放数组的地址:
前面关于指针,我们学过了几种类型的指针:
整形指针:
int* pint; 指向整形数据的指针,本身类型是int*,指针指向的地址里存放的数据类型是int
浮点型指针:
float* pf; 指向浮点型数据的指针,本身类型是float*,指针指向的地址里存放的数据类型是float
数组指针:
int (*p)[10];指向数组的指针,本身的类型是int(*)[10], 指针存放了数组的地址,这个数组有10个元素,每个元素的数据类型是int
所以p是一个指针,指向一个数组,叫数组指针。要注意:[]的优先级要高于*号的,所以必须加上()来保证p先和*结合
//数组指针
int main()
char* ch;//指向字符型数据的指针
int* a;//指向整形数据的指针
float* pf;//指向浮点型数据的指针
int(*pa)[10];//数组指针,是一个指针,指向数组的指针,指向的数组有10个元素,每个元素的类型是int整形
int* p1[10];//指针数组,是一个数组,数组里的每个元素都是指针变量,就是地址
3.2 &数组名和数组名的区别
代码如下(示例):
int main()
int a = 10;
int* p = &a;
int arr[10] = 0 ;
printf("%p\\n", arr);
printf("%p\\n", arr + 1);
printf("%p\\n", &arr[0]);
printf("%p\\n", &arr[0] + 1);
printf("%p\\n", &arr);
printf("%p\\n", &arr+1);
return 0;
这部分内容在基础阶段已经学习过,【C语言基础5——数组(1)】4.2 数组名是什么?
- arr是数组名,即是首元素地址,数值与&arr[0]、&arr相同
- &arr[0]是首元素地址
- &arr是整个数组的地址
- arr+1,地址移动到第二个int元素,移动4个字节
- &arr[0]+1,地址移动到第二个int元素,移动4个字节
- &arr+1.地址移动了一个数组的长度,移动了40个字节
由上面分析可知,&arr 的类型是: int(*)[10] ,是数组指针类型。
3.3 数组指针的使用
数组指针指向的是数组,那数组指针中存放的应该是数组的地址
int main()
int arr[10] = 1,2,3,4,5,6,7,8,9,0;
int (*p)[10] = &arr;//把数组arr的地址赋值给数组指针变量p
//但是我们一般很少这样写代码
return 0;
3.3.1 在一维数组中使用
//形参使用数组
void print1(int arr[], int sz)//传参接收的是首元素的地址,没学指针前,写成数组形式好理解
for (int i = 0; i < sz; i++)
printf("%d ", arr[i]);
printf("\\n");
//形参使用指针
void print2(int* p, int sz)//传参接收的是首元素的地址
for (int i = 0; i < sz; i++)
printf("%d ", *(p + i));//对地址解引用
printf("\\n");
//形参使用数组指针,一维数组不这样用,繁琐了
void print3(int(*p)[10], int sz)
for (int i = 0; i < sz; i++)
//p是数组指针变量,存放的数组地址,*p解引用取得数组名arr,
//数组名就是首元素的地址,*p=arr=&arr[0]
printf("%d ", *(*p+i));//对地址解引用,*(arr+i)
printf("\\n");
int main()
int arr[10] = 1,2,3,4,5,6,7,8,9,10 ;
int(*p)[10] = &arr;//指向数组的指针,将数组的地址赋值给指针变量p
int sz = sizeof(arr) / sizeof(arr[0]);
print1(arr,sz);
print2(arr, sz);
print3(&arr,sz);//一般一维数组不这样用,绕圈子了
return 0;
上面三种函数的写法,结果相同,常用的是前两种,见下图:
3.3.2 在二维数组中使用
//形参使用二维数组,最常用的数组的写法
void print1(int arr[3][5],int a,int b)
for (int i = 0; i < a; i++)
for (int j = 0; j < b; j++)
printf("%d ", arr[i][j]);
printf("\\n");
printf("\\n");
//形参使用数组指针,常用的写法, 第一行一维数组的地址用数组指针接收
void print2(int(*p)[5] , int a, int b)
for (int i = 0; i < a; i++)
for (int j = 0; j < b; j++)
printf("%d ", p[i][j]);
下面的方法也行,要复习二维数组,在二维数组中
p+i是指向第i行的,是通过地址找到第i行,&arr[i]
二维数组第i行,代表的是第i行的数组,即一个一维数组
*(p+i)解引用地址,相当于拿到了第i行,即arr[i],也相当于第i行的数组名
数组名表示首元素的地址,*(p+i) 就是第i行数组中的第一个元素的地址
*(p + i) + j是通过地址找到第i行数组中第j个元素
*(*(p + i) + j)解引用地址,拿到arr[i][j]这个元素的值
//printf("%d ", *(*(p + i) + j));
printf("\\n");
printf("\\n");
//形参使用数组指针,传入什么参数,形参就怎么定义
void print3(int(*p)[3][5], int a, int b)
for (int i = 0; i < a; i++)
for (int j = 0; j < b; j++)
printf("%d ", (*p)[i][j]);
printf("\\n");
printf("\\n");
int main()
int arr[3][5] = 1,2,3,4,5,2,3,4,5,6,3,4,5,6,7 ;
int (*p)[3][5] = &arr;//一般很少这样使用
print1(arr, 3, 5);
print2(arr, 3, 5);//传参为数组首元素地址,即第一行数组的地址
print3(&arr, 3, 5);//一般不会这样用
return 0;
调试结果见下图:
总结
本文主要学习了关于指针进阶内容的前三个知识点:
- 字符指针
- 数组指针
- 指针数组
下一篇继续学习指针进阶内容的其他知识点。
以上是关于C语言进阶4——指针的进阶的主要内容,如果未能解决你的问题,请参考以下文章