【C】940/bit2-2指针的进阶

【参考课程:B站  BV1Vm4y1r7jY】

//指针是用于存放地址的变量,地址唯一标识一块内存空间。
//指针的大小是固定的4/8个字节(32/64位平台)
//指针的类型 决定了指针的+-整数的步长,以及指针解引用操作的权限
//指针的运算

1.字符指针 char*

#include<stdio.h>
int main()
{
//字符指针可以存放一个字符变量的地址
	char ch = 'c';
	char* pch = &ch;
//字符指针可以存放字符串首字符的地址//本质还是存放字符的地址
	char* p = "abcdef";
	char chr[] = "abcdef";
		//将字符串[a][b][c][d][e][f][\0]的首字符[a]的【地址】存放在p中
	printf("%c\n", *p);//a//解引用地址p,%c:输出其中存放的字符
	printf("%c\n", p);//?//把地址p:0x00007ff6e3369ca4,%c:以字符形式输出
	printf("%s\n", p);//abcdef//从起始地址(p存放的'a'的地址)开始打印字符串
		//%s:需要给定一个地址,%s从这个地址开始依次输出字符,直到遇到字符[\0]停止
	//与数组名类似:
	printf("%s\n", chr);//abcdef
	return 0;
}

 注意:

char* p = "abcdef";

是将常量字符串"abcdef"的首字符地址赋给 p

常量字符串的内容不能被更改,所以此处严谨书写代码应为:  //const修饰指针变量

const char* p = "abcdef";

【例题】

#include<stdio.h>
int main()
{
	const char* p1 = "abcdef"; 
	const char* p2 = "abcdef";
	//"abcdef"为常量字符串,在内存中储存在【只读数据区】
		//【只读数据区】内储存的数据只可读取使用,不可做更改--相同的数据在【只读数据区】内只储存1份
	//p1 p2都存放的是储存在【只读数据区】的常量字符串"abcdef"的首字符地址→∴p1 == p2
	if (p1 == p2)
		printf("p1==p2\n");
	else
		printf("p1!=p2\n");

	char arr1[] = "abcdef";
	char arr2[] = "abcdef";
	//此处arr1 arr2创建了2个独立数组,这两个数组内容可变,只是数组的初始化恰巧相同
	//数组名是数组首元素地址→arr1 arr2指向两个不同数组的首元素地址→∴arr1 != arr2
	if (arr1 == arr2)
		printf("arr1==arr2");
	else
		printf("arr1!=arr2");
	return 0;
}

结果输出:

2.指针数组

//指针数组--是数组,是用于存放指针的数组

int* arr1[3]; //存放整型指针的数组
char* arr2[7]; //存放字符指针的数组
char** arr3[21]; //存放二级字符指针的数组

【例】用指针数组将一维数组模拟组合成二维数组

#include<stdio.h>
int main()
{
	int arr1[4] = { 1,2,3,4 };
	int arr2[4] = { 2,3,4,5 };
	int arr3[4] = { 3,4,5,6 };
	int arr4[4] = { 4,5,6,7 };
	int arr5[4] = { 5,6,7,8 };
	int* parr[5] = { arr1,arr2,arr3,arr4,arr5 };
	for (int i = 0; i < 5; i++)
	{
		for (int j = 0; j < 4; j++)
		{
			printf("%d ", *(parr[i] + j));
            //p[i] <==> *(p+i)
            //∴此处还可写为:
          //printf("%d ", *(parr[i][j]);
		}
		printf("\n");
	}
	return 0;
}

⭐不同:

二维数组在内存中连续存放

而用指针数组将一维数组模拟组合成二维数组,其中的一维数组与一维数组之间内存不一定连续

指针数组可用于存储字符串

3.数组指针 int(*)[n]

//类型:int(*)[n]   //int表示数组元素类型;n为数组元素个数,不可省略
//数组指针--是指针,是指向数组的指针,用于存放数组的地址

int* p1[10]; //p1是指针数组,数组元素类型是int*--整型指针
int(*p2)[10]; //p2是【数组指针】指向有10个元素的int类型数组
int arr[10] = { 0 };
int* p1 = arr; //p1存放【数组首元素】地址
int(*p2)[10] = &arr; //p2存放【整个数组】arr的地址

char* arr[5] = { 0 }; //arr[5]是指针数组
char* (*pc)[5] = &arr; //pc存放arr[5]数组的地址,pc是数组指针--类型:char*(*)[5]
​

⭐再次讨论数组名

  1. 数组名通常表示的都是数组首元素地址
    #include<stdio.h>
    int main()
    {
    	int arr[10] = { 0 };
    	printf("%p\n", arr); //0000003B4A0FFB48
    	printf("%p\n", &arr[0]); //0000003B4A0FFB48
    	return 0;
    }
  2. 但有2个例外
    1. sizeof(数组名)  -这里的数组名表示整个数组,计算的是整个数组的大小
      //注意括号里只单独放数组名
      #include<stdio.h>
      int main()
      {
      	int arr[10] = { 0 };
      	printf("%d\n", sizeof(arr)); //40 //整个数组的字节大小
      	printf("%d\n", sizeof(arr+0)); //8 //此处打印的是类型为 int* 的变量的字节大小
              //sizeof(arr+i)打印的是指向数组元素arr[i]的指针的大小
              //arr+0表示数组arr的首地址加上偏移量0,实际上就是指向数组第一个元素的指针。
      	printf("%d\n", sizeof(arr[0])); //4 //单个元素的字节大小
      	return 0;
      }
    2. &数组名  -取出的是整个数组的地址
      #include<stdio.h>
      int main()
      {
      	int arr[10] = { 0 };
      	printf("%p\n", arr); //0000007307EFF548
      	printf("%p\n", arr+1); //0000007307EFF54C==0000007307EFF548 + 4
      
      	printf("%p\n", &arr); //0000007307EFF548
      	printf("%p\n", &arr+1); //0000007307EFF570==0000007307EFF548 + 40
      	return 0;
      }

数组指针的运用:

  1. *(数组指针) --本质是数组名--数组首元素地址
    ⭐<使用数组指针打印数组>可行,但非常不建议使用这种操作
    #include<stdio.h>
    int main()
    {
    	int arr[] = { 0,1,2,3,4,5,6,7,8,9 };
    	int(*parr)[10] = &arr;
    	//parr指向数组→*parr找到数组整体,相当于数组名→数组名是首元素地址
    	//∴ *parr 本质上是数组首元素地址
    /*使用数组指针parr打印整个数组*/
    	int i = 0;
    	int sz = sizeof(arr) / sizeof(arr[0]);
    	for (i = 0; i < sz; i++)
    	{
    		printf("%d ", (*parr)[i]);
    	  //printf("%d ", *(*parr + i)); 效果相同
    	}
    	return 0;
    }
  2. 数组指针的常见使用方法:
    二维数组数组名 == 二维数组首元素地址 == 二维数组的第一行数组的数组地址
         *(二维数组名)
    == (二维数组第一行)一维数组的数组名
         *(二维数组名+n)
    == (二维数组)n行一维数组的数组名
    #include<stdio.h>
    int main()
    {
    	int a[3][5] = { 1,2,3,4,5,2,3,4,5,6,3,4,5,6,7 };
    /*数组名--表示数组首元素地址   二维数组首元素为第一行数组
     ∴二维数组数组名==第一行数组的数组地址*/
    	
    	//自定义函数printarr打印二维数组
    	void printarr(int(*arr)[5], int row, int col);//形参名分别为 arr, row, col
    	//由于这里二维数组的第一行数组有5个元素,
    	//∴要把二维数组的数组名 传参的参数类型写为:int(* )[5]  
    
    	printarr(a, 3, 5);//传参调用函数
    	return 0;
    }
    void printarr(int(*arr)[5],int row, int col)
    {
    	for (int i = 0; i < row; i++)
    	{
    		for (int j = 0; j < col; j++)
    		{// *(二维数组名+n) == (二维数组)n行一维数组的数组名
    			printf("%d ", *(*(arr+i)+j));
              //printf("%d ", (*(arr+i))[j]); 效果相同 
                              //[]优先级大于*的优先级,所以要把*(arr+i)括起来
    		}
    		printf("\n");
    	}
    }

4.数组参数、指针参数

5.函数指针

6.函数指针数组

7.指向函数指针数组的指针

8.回调函数

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值