一文全揽C/C++中所有指针相关知识点(从原理到示例,学不完根本学不完!!!!)

news2024/11/19 15:37:40

在这里插入图片描述

本篇会对C/C++中【常见指针相关知识】一直进行总结迭代,记得收藏吃灰不迷路,一起学习分享喔

请大家批评指正,一起学习呀~

  • 一、指针基本知识
    • 1.1 指针的定义
    • 1.2 (*) 和( &) 运算符
    • 1.3 如何声明指针变量
    • 1.5 指针解决函数间通信问题
  • 二、指针与数组的关系
    • 2.1 指针与整数、指针与指针的加减运算
    • 2.2 数组形参的写法
    • 2.3 指针递增练习
    • 2.4 指针数组和数组指针
      • 2.4.1 指针数组定义
      • 2.4.2 指针数组示例
      • 2.4.3 指针数组小tips:一个for循环便利二维数组
      • 2.4.4 数组指针定义
      • 2.4.5 数组指针示例
      • 2.4.6 数组指针小tips:利用数组指针去打印二维数组
      • 2.4.7 数组的传参使用
    • 2.5 结构指针
    • 2.6 指针的地址、指针的值、指针所指向内容的值
    • 2.7 void类型的指针
    • 2.8 函数指针
  • 三、二级指针(较难喔,坚持住咯)
    • 3.1 二级指针的概念
    • 3.2 二级指针的示例
    • 3.3 二级指针的用途
  • 四、多级指针(万变不离其宗)
  • 五、指针和多维数组
  • 六、指针和字符串的关系

一、指针基本知识

1.1 指针的定义

指针是一个值为内存地址变量(或数据对象)。首先指针是一个变量,它的值就是某个变量的内存地址,就好比 int 类型的变量它的值是整数也是一样的。
从一个例子来着手叭:

#include <stdio.h>
#include <stdlib.h>
int main(void){
	int room = 2;
	//定义两个指针变量指向room
	int *p1 = &room;
	int *p2 = &room;
	printf("room 地址:0x%p\n", &room);
	printf("p1 地址:0x%p\n", &p1);
	printf("p2 地址:0x%p\n", &p2);
	printf("room 所占字节:%d\n", izeof(room));
	printf("p1 所占字节:%d\n", sizeof(p1));
	printf("p2 所占字节:%d\n", sizeof(p2));
	system("pause");
	return 0

示例中定义了一个int类型的变量room,定义了两个指向int类型的指针p1和p2指向room。此时room的地址(&是取地址运算符)printf("room 地址:0x%p\n", &room);就是指针p1和p2的值,但p1和p2的地址又是两个不同的值,跟room的地址完全是两回事儿。

在这里插入图片描述

1.2 (*) 和( &) 运算符

假设有个指向 int 类型的指针ptr:int *ptr;
有个 int 类型的变量:int bat;
假设 ptr = & bat;即 ptr 指向 bat。
此时使用间接运算符或者解引用运算符*后面跟上指针ptr(*ptr)就可以拿到指针指向内存地址上存储的值。上式组合可得:
ptr = & bat;ptr指向bat,即bat的地址赋给了ptr
val = *ptr;val指向ptr的值,即ptr指向地址上的值赋给了val。
(* ptr是指针ptr指向地址上的值,即p的值是一个内存地址是一个变量,它指向的值是* p,是内存地址上存储的值)
===> val = bat;
——————————————————————————————————————
示例:
nurse = 2;
ptr = &nurse;
val = *ptr;
最终得到:
val = 2;
——————————————————————————————————————
总结:
1、&取地址运算符后面跟一个变量名时,就可以拿到该变量的地址。&nurse就可以拿到nurse的地址
2、*解引用运算符后面跟一个指针或者地址的时候,可以拿到该地址上存储的值
3、&取地址运算符*解引用运算符从一定层面上看作是可以相互抵消的

1.3 如何声明指针变量

指针变量的声明必须指定指针指向变量的类型,因为不同类型的变量所占用的内存大小不同。
指针变量声明如下:
int *pi;//pi是指向int类型变量的指针
char *pc;//pc是指向char类型变量的指针

需要注意:
32 位系统中,int 整数占4 个字节,指针同样占4 个字节
64 位系统中,int 整数占4 个字节,指针同样占8 个字节
但这不是个例啦,
在 32 位平台下,无论指针的类型是什么,sizeof(指针名)都是 4.
在 64 位平台下,无论指针的类型是什么,sizeof(指针名)都是 8.

#include <stdio.h>
#include <stdlib.h>
int main(void){
	int room = 2 ;
	int room1 = 3 ;//3p
	int *p1 = &room;
	int *p2 = p1;//int *p2 = &room;
	//1.访问(读、写)指针变量本身的值,和其它普通变量的访问方式相同
	int *p3 = p1;
	printf("room 的地址: %d\n", &room);//6222525
	printf("p1 的值: %d p2 的值: %d\n", p1, p2);//p1 = 6222525,p2 = 6222525
	printf("p3 的值: %d\n", p3);//p3 = 6222525
	p3 = &room1;
	printf("p3 的值: %d, room1 的地址:%d\n", p3, &room1);//不建议用这
	种方式
	//使用16 进制打印,把地址值当成一个无符号数来处理
	printf("p1=0x%p\n", p1);
	printf("p1=0x%x\n", p1);
	printf("p1=0x%X\n", p1);
	system("pause");
	return 0;
}

示例中我们在对指针的值打印的时候一般采用十六进制的%p(ANSIC专门为指针提供的转换说明%p),或者直接采用十六进制0x%x、0x%X打印

1.5 指针解决函数间通信问题

这也是使用指针的主要原因之一,因为被调函数没有办法修改函数的实参,所以只能采用指针的形式将参数的地址传过去,即被调函数中改变主调函数的变量(被调函数中一班不会改变主调函数的值,如果需要的话就要使用指针作为参数)
首先看一个程序示例:需要一个函数交换x和y的值,就需要将x和y的地址作为参数传递给被调函数。

#include <stdio.h>
#include <stdlib.h>
void interchange(int *u,int *v);
int main(void){
	int x = 5,y = 10;
	printf("Originally x = %d and y  = %d\n",x,y);
	interchange(&x,&y);
	printf("Now x = %d and y  = %d\n",x,y);
	system("pause");
	return 0;
}
void interchange(int *u,int *v){
	int temp;
	temp  = *u;
	*u = *v;
	*v = temp; 
}
//output
Originally x = 5 and y  = 10
Originally x = 10 and y  = 5

如此,便能理解为什么输入函数scanf("%d",&num)了,因为它是将读取的值存储到指定的地址上。

二、指针与数组的关系

使用指针的程序会更有效率,尤其在处理数组的时候,而且数组跟指针的关系十分密切,数组名就是数组首元素的地址,假如arr是一个数组,则下式成立:

arr = &arr[0]
arr&arr[0]都是数组首元素的地址(首元素内存地址)
arr 是数组首元素地址,&arr 整个数组的首地址,地址是一样的,只是意义不同。

dates是数组首元素的地址,dates + index 是数组第index个元素dates[index]的地址,*(dates + index)是该元素的值。

数组的地址就是数组首元素的地址

2.1 指针与整数、指针与指针的加减运算

C中指针加1指的是增加一个存储单元,对于数组来讲就是意味着加1后的地址是下一个元素的地址,而不是下一个字节的地址。因为在数组中每个元素所占用的字节大小是固定的,所以指针加1,指针的值递增它所指向类型的大小,比如指向的是int类型的数组,那么指针加1,指针的值直接递增4个字节,也就是指向下一个元素了。以下面short类型数组举例。

请添加图片描述
pti是short类型的指针,所以每次指针加1,pti的值就会递增2个字节,2个字节刚好是一个数组元素的大小,所以指针加1,指针的指向就往下走一步。

总结:
1、 指针加一个数之后与数组之间的关系
dates = &dates[0];
dates + 2 = &dates[2];//相同的地址
*(dates + 2) = dates[2];//相同的值
模板:
dates + n = &dates[n];//相同的地址
*(dates + n) = dates[n];//相同的值

*(dates + n)dates + n 的区别:
*(dates + n):表示dates的第n个元素的值
dates + n:表示dates的第1个元素的值+n

2、指针与整数的运算,指针加减数字表示的意义是指针在数组中位置的移动;对于整数部分而言,它代表的是一个元素,对于不同的数据类型,其数组的元素占用的字节是不一样的,
比如指针+ 1,并不是在指针地址的基础之上加1 个地址,而是在这个指针地址的基础上加1 个元素占用的字节数

  1. 如果指针的类型是char*,那么这个时候1 代表1 个字节地址
  2. 如果指针的类型是int*,那么这个时候1 代表4 个字节地址
  3. 如果指针的类型是float*,那么这个时候1 代表4 个字节地址
  4. 如果指针的类型是double*,那么这个时候1 代表8 个字节地址

3、通用公式:
数据类型 *p;
p + n 实际指向的地址:p 基地址+ n * sizeof(数据类型)
p - n 实际指向的地址:p 基地址- n * sizeof(数据类型)

比如:
1)对于int 类型,比如p 指向0x0061FF14,则:
p+1 实际指向的是0x0061FF18,与p 指向的内存地址相差4 个字节;
p+2 实际指向的是0x0061FF1C,与p 指向的内存地址相差8 个字节
2)对于char 类型,比如p 指向0x0061FF28,则:
p+1 实际指向的是0x0061FF29,与p 指向的内存地址相差1 个字节;
p+1 实际指向的是0x0061FF2A,与p 指向的内存地址相差2 个字节;

4、指针与指针之间的加减运算
我们先总结再看示例,知识点:
(1)指针和指针可以做减法操作,但不适合做加法运算;
(2)指针和指针做减法适用的场合:两个指针都指向同一个数组,相减结果为两个指针之
间的元素数目,而不是两个指针之间相差的字节数。

比如
int int_array[4] = {12, 34, 56, 78};
int *p_int1 = &int_array[0];
int *p_int2 = &int_array[3];
p_int2 - p_int1 的结果为3,即是两个指针之间的元素数目为3 个。
如果两个指针不是指向同一个数组,它们相减就没有意义。

3)不同类型的指针不允许相减
比如:
char *p1;
int *p2;
p2-p1 是没有意义的。

2.2 数组形参的写法

在函数原型和函数定义中,可以使用 int arr[] 代替 int * arr
int arr[] 和 int * arr 两种形式都表示arr是一个指向 int 类型的指针。如下图所示中列举了很多诸多相似的写法,一起学习一下。
请添加图片描述
接下来分别演示用数组表示法和指针法进行数组求和运算。数组表示法就是将整个数组作为参数传递,指针表示法就是将数组名也就是首元素地址或者说是指针作为参数传递。
1、首先用数组表示法进行求和

int main(void){
	int marble[10] = {……};//省略不写啦
	int answer = sum(marble,10);
	printf("%ld",answer);
}
int sum(int arr[],int N){
	int total = 0;
	for(int i = 0;i < 10;i++){
		total += arr[i];
	}
	return total;
}

2、首先用指针表示法进行求和

int main(void){
	int marble[10] = {……};//省略不写啦
	int answer = sum(marble,marble + 10);
	printf("%ld",answer);
}
int sum(int *start,int *end){
	int total = 0;
	while(start < end){
		total += *start;
		start++;
	}
	return total;
}

start++递增指针变量start是指向数组的下一个元素,因为start是指向int的指针,所以start+1相当于其值递增int类型的大小。

2.3 指针递增练习

1、total = *start ++total = *++start;这两个语句是非常常见且非常重要的。(++* 的优先级相同

2、total = *start ++;表示:先将指针指向位置上的值赋给total,然后在递增指针

3、total = *++start ;表示:先递增指针,再将指针指向的值赋给total

经典练习:

#include <stdio.h>
int data[2] = {100,200};
int moredata[2] = {300,400};
int main(void){
	int * p1,*p2,*p3;
	p1 = p2 = data;
	p3 = moredata;
	printf("*p1 = %d,*p2 = %d, *p3 = %d\n",*p1,*p2,*p3);
	printf("*p1++ = %d,*++p2 = %d, (*p3)++ = %d\n",*p1++,*++p2,(*p3)++);
	printf("*p1 = %d,*p2 = %d, *p3 = %d\n",*p1,*p2,*p3);
}

输出:

请添加图片描述
第一行输出应该是没有问题的,因为:
p1 = p2 = data;
p3 = moredata;
所以:
p1 = p2 = data = &data[0];->*p1 = *p2 = *data = *(&data[0]) = &data[0] = 100;
p3 = moredata; ->*p3 = *moredata = *(&moredata[0]) = moredata[0] = 300;

第二行输出:

*p1++:是先打印p1所指地址上的值,在进行递增。所以结果为:p1所指地址上的值100,但展示结果之后p1指针便已自增,指向data[1]上
*++p2:先进行指针递增,p2指向data[1]上,在输出指针指向位置上的值200
(*p3)++:先将p3指向位置的值输出300,在进行值的递增

因为来到第三行:

*p1 = 200,*p2 = 200,*p3 = 301

注意:
1、*p1++(*p1)++是不同滴,虽然++* 的优先级相同,但是结合律有顺序,是从右向左的,所以*p1++是先执行p1++再执行*p1的。total = *p1++先将p1指向的值赋给total,但还是先进行p1++,因为根据自增运算规律可知,p1++之后并不会立刻改变值,而是先使用再递增嘛,所以它跟(*p1)++不同,前者++的时候是指针递增,而后者递增的时候是值的递增。

2、P++(P是指针)的概念是在P当前地址的基础上,自增P对应类型的大小,即P = P+1*(sizeof(类型))

2.4 指针数组和数组指针

想要理解指针数组和数组指针的区别,很简单。来看两个小练习就明白辽。
根据题目要求,正确的声明变量:

2.4.1 指针数组定义

A:psa是一个内含20个元素的数组,每个元素都是指向int的指针。
这种我们将其称为指针数组,即装着指针的数组int *(p1[20]);

定义:类型 * (指针数组名[元素个数])

其中p1是数组名称
如下图所示:int * (p1[5]),数组p1内含5个int类型的指针
在这里插入图片描述


2.4.2 指针数组示例

指针数组的示例:指针数组可以被用来记录最高点和次高点的地址,最后通过解应用可以拿到最高与次高点的值

#include <stdio.h>
#include <stdlib.h> 
int main(void){ 
	//二维矩阵中找到身高最高和次高的值
	int girls[4][3] = { 
		{173, 158, 166}, 
		{168, 155, 171}, 
		{163, 164, 165}, 
		{163, 164, 172} };
	//定义一个有两个元素的指针数组,每个元素都是一个指针变量
	//定义两个指针放进指针数组中,让他们分别指向最高和次高的地址
	//qishou[0]中最高的地址,qishou[1]中次高的地址
	//同理如果要找出前十个身高最高的,直接将2换成10即可
	int* (qishou[2]);
	//base case 先通过前两个身高分别定出最高和次高放入指针数组中
	if (girls[0][0] > girls[0][1]) { 
		qishou[0] = &girls[0][0];//最高 
		qishou[1] = &girls[0][1]; //次高
	}
	else { 
		qishou[0] = &girls[0][1]; //最高 
		qishou[1] = &girls[0][0];  //次高
	}
	//让其他元素与最高和次高进行比较,总共12个元素
	for (int i = 2; i < 12; i++) {
		//girls[i/3][i%3] 非常巧妙的一个循环就可以遍历二维数组的方法
		//如果新身高小于等于此身高就直接略过
		if(*qishou[1] >= girls[i/3][i%3]){ 
			continue; 
		}
		//候选者高于次高
		//1.候选者比"冠军"矮 
		if(girls[i/3][i%3] <= *qishou[0]){ 
			qishou[1] = &girls[i/3][i%3]; 
		}else { 
			//2.候选者比"冠军"高 
			qishou[1] = qishou[0]; 
			qishou[0] = &girls[i/3][i%3]; 
		} 
	}
	printf("最高的身高: %d , 次高的身高: %d\n", *qishou[0], *qishou[1]);
	system("pause");
	return 0; 
}

在这里插入图片描述


2.4.3 指针数组小tips:一个for循环便利二维数组

tips:插播一个小知识点:一个for循环便利二维数组
在这里插入图片描述


2.4.4 数组指针定义

B:p1是一个指向数组的指针,数组内含有20个char类型的值。
这种我们将其称为数组指针,即指向数组的指针int (*p1)[20];

定义:类型 (*数组指针名)[元素个数]

其中p1是指针名称
如下图所示:int (*p2)[5],数组指针p2指向内含5个int类型数据的数组
在这里插入图片描述


2.4.5 数组指针示例

数组指针的示例:
使用数组指针访问数组的两种方式:
数组法: (*p)[j]
指针法: *((*p)+j)

假设有题目:据同学们报告,A 栋学生楼有学生用高倍望眼镜偷看别人洗澡,宿管办领导决定逐个宿舍排查,得到的线报是A0 到A3 宿舍的某个子最矮的男生:以二维数组表示宿舍,某宿舍个子最小也就是说二位数组中的最小值

下面分别使用数组下标法和指针法来解决

#include <stdio.h>
#include <stdlib.h>
int main()
{
	//四个宿舍分别是A0~A3
	int A[4][3]={{173, 158, 166},
	{168, 155, 171},
	{163, 164, 165},
	{163, 164, 172}};
	//定义一个指向三个成员的数组的指针
	//用来指向二维数组中的某一行
	int (*p)[3]; 
	//定义一个空指针,最后指向最爱身高的地址
	//没空指针没有指向任何地址
	int * boy = NULL;
	//p指向第一个数组,A[0]恰好有三个int类型的数据
	p = &A[0];
	
	//第一种数组下标法
	//四个宿舍
	/*for(int i=0; i<4; i++){
		//每个宿舍三个成员
		for(int j=0; j<3; j++){
			//(*p) 等同于A[0],A[0][0]等同于(*p)[0]
			printf(" %d", (*p)[j]); 
		}
		printf("\n");
		p++; //p++ = &A[1]
	}*/
	//将新定义的指针首先指向第一个元素的位置,假定它是最小的身高
	boy = &(*p)[0];//(*p)[0] = A[0][0]
	//boy = (*p);
	
	//第二种指针访问法
	//数组成员: *p *(p+1) *(p+2)
	//p = a,*p = a[0]![请添加图片描述](https://img-blog.csdnimg.cn/2dab615237474fa9a873eda2a0ca5a39.png)

	for(int i=0; i<4; i++){
		for(int j=0; j<3; j++){
		//打印二位数组的方法
			printf(" %d", *((*p)+j)); 
			//找出最矮个字的数字
			//后面的数字如果大于首元素
			if( *boy > *((*p)+j)){
			//将后面元素的地赋值给最小身高的地址
				boy = (*p)+j;
			}
		}
		printf("\n");
		p++;
	}
	printf("偷窥的学生是: %d\n", *boy);
	system("pause");
	return 0;
}

2.4.6 数组指针小tips:利用数组指针去打印二维数组

tips:插播一个小知识点:利用数组指针去打印二维数组请添加图片描述
int (*p)[3];
p = &A[0];
*p = A[0];
要是:
p++;
则:
*p = A[1];

(*p)[0] = A[1][0];
(*p)[1] = A[1][1];

第二种方法:
请添加图片描述
数组指针的定义:int(*p)[3];
p = &A[0]->*p = A[0]->(*p)+j = A[0][j] 的地址->*((*p)+j ) = A[0][j]的值


2.4.7 数组的传参使用

数组传参时,会退化为指针!,所以被调函数中可以用指针来接收
(1)退化的意义:C 语言只会以值拷贝的方式传递参数,参数传递时,如果只拷贝整个数
组,效率会大大降低,并且在参数位于栈上,太大的数组拷贝将会导致栈溢出。
(2)因此,C 语言将数组的传参进行了退化。将整个数组拷贝一份传入函数时,将数组名看做常量指针,传数组首元素的地址。

一维数组传参退化为一级指针:
被调函数中形参为:int * arr;
请添加图片描述

二维数组传参退化为二级指针:
被调函数中形参为:int ** arr;
栗子就不举啦!!!

2.5 结构指针

结构指针请参考这边喔~C语言复合类型之结构(struct)篇(结构指针)

2.6 指针的地址、指针的值、指针所指向内容的值

请添加图片描述
图中可以总结出:
1、p的值就是i的地址&i
2、*p就是指针所指向内存单元的数据,即指针所指向内存地址上存储的值
3、&p指指针本身的地址
4、&*p的值跟p是一样的,都是i的地址&i

2.7 void类型的指针

void是一个空类型,作为函数返回值值类型(即不要求返回值)。
void* => 空类型指针,只存储地址的值,丢失类型,无法访问,要访问其值,我们必须对这个指
针做出正确的类型转换,然后再间接引用指针。

1、所有其它类型的指针都可以隐式自动转换成void 类型指针,反之需要强制转换
2、而且void类型指针不允许++这种算数运算
3、void类型指针是很常见滴嗯哼

请添加图片描述

2.8 函数指针

首先让我们思考一下,函数是否有地址?写个小代码试试看叭~请添加图片描述
由上图可知函数确实存在地址,那什么是函数指针呢?
指向数组的指针称为:数组指针
指向函数的指针称为:函数指针
指向函数的指针中存储着函数代码的起始处的地址

函数指针的定义:函数返回值类型 (*指针名)(函数参数列表类型)

例如:
原本函数:int compare_char(const void *a, const void *b)
int (*fp)(const void *, const void *);
因此: (*fp)是一个参数列表为(const void *, const void *)、返回值类型为int的函数
其实很简单,就是将函数名 compare_char替换成 (*fp)即可

需要注意:int (*fp)(const void *, const void *)中的()不能少,因为运算优先级的问题。

小总结一下:如何声明函数指针:
将函数原型中函数名直接换成(*p)即可,p是自定义的指针名

三、二级指针(较难喔,坚持住咯)

只要理解了上面指针的一些性质,相信我们一定可以顺水推舟推敲出二级指针是个什么玩意儿哈哈哈。

3.1 二级指针的概念

二级指针也是一个普通的指针,只是二级指针的值是一级指针的地址罢了。
一级指针:指向一个普通变量,并保存该普通变量的地址;
二级指针:指向一个一级指针,并保存该一级指针的地址;

int guizi1 = 888;
int *guizi2 = &guizi1; //1 级指针,保存guizi1 的地址
int **liujian = &guizi2; //2 级指针,保存guizi2 的地址,guizi2 本身是一个一级指针变量

3.2 二级指针的示例

刘建手里持有第一个柜子的地址
第一个柜子里面是第二个柜子的地址
第二个柜子里面是第三个柜子的地址
第三个柜子里面放着888

在这里插入图片描述

#include <stdio.h>
#include <stdlib.h>
int main(void){
	int guizi2 = 888; //存枪的第3个柜子
	int *guizi1 = &guizi2; //存第3 个柜子地址的第2个柜子
	int **liujian = &guizi1; //手握第一个柜子地址的刘建
	printf("刘建打开第一个柜子,获得第二个柜子的地址:0x%p\n", *liujian);
	printf("guizi2 的地址:0x%p\n", &guizi2);
	int *tmp;
	tmp = *liujian;
	printf("访问第二个柜子的地址,拿到枪:%d\n", *tmp);
	printf("刘建一步到位拿到枪:%d\n", **liujian); //缩写成**liujian
	system("pause");
	return 0;
}

请添加图片描述
结果分析:
int guizi2 = 888; //存枪的第3 个柜子
int *guizi1 = &guizi2; //存第3 个柜子地址的第2个柜子
int **liujian = &guizi1; //手握第一个柜子地址的刘建


二级指针的解引用【重点知识】:

1、二级指针liujian的一次解引用 **liujian就可以得到被指向指针的地址;
2、二级指针进行两次解引用就可以得到所指的一级指针所指地址的值;
第一次解应用:*liujian = guizi1 = &guizi2
第二次解引用:![请添加图片描述](https://img-blog.csdnimg.cn/b067977535c74fe7894305bfe0d43440.png)


则:
请添加图片描述
**liujian一步到位的取法可以直接得到二级指针所指以及指针地址上的值。
二级指针的解引用非常重要,需要牢记!!

3.3 二级指针的用途

  1. ==一级指针可以将主调函数中的变量通过参数“带入”被调函数内部进行修改,但没办法将被调函数中的内部变量“带出”到主调函数中

我们知道使用指针可以在被调函数中修改主调函数中变量的值,如下:
在这里插入图片描述
但是想要把被调函数中的内部变量“带出”到主调函数中需要用到双指针,如下所示,被调函数 boy_home中的内部变量boy拿到主调函数中进行打印
在这里插入图片描述
其中*meipo = &boy;表示将二级指针的值,即一级指针的来存储boy的地址
最后通过printf("boy: %d\n", *meipo);中的*meipo拿到一级指针地址上的值23
2. 二级指针可以不但可以将变量通过参数”带入“函数内部,也可以将函数内部变量“带出”到函数外部。

四、多级指针(万变不离其宗)

工作中二级指针时有见到,多级指针其实已经很少啦
声明办法如下:
int guizi1 = 888;
int *guizi2 = &guizi1; //普通指针
int **guizi3 = &guizi2; //二级指向一级
int ***guizi4 = &guizi3; //三级指向二级
int ****guizi5 = &guizi4; //四级指向三级
……
在这里插入图片描述

五、指针和多维数组

前面我们在打印二维数组的时候,已经体现出了指针和二维数组的关系啦,在这儿我们重新总结记录一下

p302

六、指针和字符串的关系

指针在字符串定义时的作用
指针的地址和指针的值,两者的区别,用p328页处的的例题来进行说明

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/669804.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

SM国密算法(四) -- SM3算法

一、简介 SM3密码杂凑算法是中国国家密码管理局2010年公布的中国商用密码杂凑算法标准。适用于商用密码应用中的数字签名和验证。 SM3是在[SHA-256]基础上改进实现的一种算法&#xff0c;其安全性和SHA-256相当。SM3和MD5的迭代过程类似&#xff0c;也采用Merkle-Damgard结构。…

OpenCV(图像处理)-基于python-滤波器(低通、高通滤波器的使用方法)

1.概念介绍2. 图像卷积filter2D() 3. 低通滤波器3.1 方盒滤波和均值滤波boxFilter()blur() 3.2 高斯滤波&#xff08;高斯噪音&#xff09;3.3 中值滤波&#xff08;胡椒噪音&#xff09;3.4 双边滤波 4. 高通滤波器4.1Sobel&#xff08;索贝尔&#xff09;&#xff08;高斯&am…

STL之set和map

目录 一. 原型二. 模板参数适配三. 迭代器四. 插入函数的修改四. 代码 一. 原型 简单实现的红黑树 template<class K, class V> struct RBTreeNode {RBTreeNode<K, V>* _left;RBTreeNode<K, V>* _right;RBTreeNode<K, V>* _parent;pair<K, V> …

FPGA_学习_11_IP核_RAM_乒乓操作

本篇博客学习另一个IP核&#xff0c;RAM。 用RAM实现什么功能呢&#xff1f; 实现乒乓操作。 乒乓操作是什么呢&#xff1f; 参考&#xff1a; FPGA中的乒乓操作思想_fpga中乒乓操作的原因_小林家的龙小年的博客-CSDN博客 何为乒乓操作_fanyuandrj的博客-CSDN博客 以下是本人理…

Clion开发STM32之日志模块(参考RT-Thread)

前言 日志对于开发和排错方面有着很重要的影响。通过查看RT-Thread的源码&#xff0c;将日志的打印输出划分到具体的文件和通过宏定义对具体的日志等级进行划分&#xff0c;这样就比较方便。结合此源码的形式将其分离出来&#xff0c;作为自己项目的日志框架进行使用分为日志驱…

crossover软件下载2023最新版虚拟机

在Mac系统中一直存在一个比较令用户们头疼的问题&#xff0c;那就是安装不了想要的Windows软件。如果使用的第一台电脑就是MacBook那接触到的Windows软件想必并不是很多。但我们中的大多数人都是从小先学习了Windows的操作系统&#xff0c;再过渡到Mac系统上的。 那有小伙伴会…

最新基于MATLAB 2023a的机器学习、深度学习实践应用

MATLAB 2023版的深度学习工具箱&#xff0c;提供了完整的工具链&#xff0c;使您能够在一个集成的环境中进行深度学习的建模、训练和部署。与Python相比&#xff0c;MATLAB的语法简洁、易于上手&#xff0c;无需繁琐的配置和安装&#xff0c;能够更快地实现深度学习的任务。 M…

Flink流批一体计算(4):Flink功能模块

目录 Flink功能架构 Flink输入输出 Flink功能架构 Flink是分层架构的分布式计算引擎&#xff0c;每层的实现依赖下层提供的服务&#xff0c;同时提供抽象的接口和服务供上层使用。 Flink 架构可以分为4层&#xff0c;包括Deploy部署层、Core核心层、API层和Library层 部署层…

基于SSM的宠物领养系统的设计与实现

1.引言 动物作为人类的宠物已经有几千年的历史了&#xff0c;尤其是猫和狗因其天性被人类所喜爱和推崇&#xff0c;好多的成语故事、俗语等都及它们有关。但是&#xff0c;近几年来由于生活节奏的加快&#xff0c;人们的压力增大&#xff0c;没有时间和空间去照顾宠物&#xf…

ProGuard 进阶系列(三) Java 类文件解析

书接上文&#xff0c;当我们从用户的配置文件中读取到所有的配置信息后&#xff0c;下一步便是将配置中的指定的类文件进行读取&#xff0c;构建需要混淆的 Java 类文件的语法树。在阅读类文件之前&#xff0c;先来看一下输入输出参数中的内容&#xff0c;我使用的是一个 Andro…

大一下暑期计划 + 2023字节青训营预告直播

目录 &#x1f33c;前言 &#x1f339;后端学习方法 &#x1f333;1&#xff0c;层次 &#x1f333;2&#xff0c;体系 &#x1f333;3&#xff0c;算法和数据结构 &#x1f333;4&#xff0c;总结 &#x1f339;前端学习方法 &#x1f333;基础 &#x1f339;求职中如…

如何在Microsoft Excel中使用LEN函数

如果你曾经想尝试查找一行文本中的字符数&#xff0c;你可以使用Microsoft Excel来查找&#xff0c;这要归功于LEN函数。以下是如何使用它。 一、什么是 LEN 函数 LEN函数是一个简单的计算函数&#xff0c;用于计算给定文本字符串中的所有字符&#xff0c;包括数字、字母、特…

【数据库课设】图书馆资源管理系统 源码+流程图+结构设计(借还图书 逾期罚款 图书管理 读者管理 信息查询)python实现

文章目录 一 实现功能&#xff08;1&#xff09;管理员功能&#xff08;2&#xff09;读者功能 二 数据流图三 概念结构设计四 文件目录五 源码&#xff1a;main.py六 运行截图 一 实现功能 &#xff08;1&#xff09;管理员功能 一个管理员编号对应一个密码&#xff0c;且需…

redis—安装以及可视化

前言 redis 是一种非关系型数据库&#xff0c;什么是非关系型数据库&#xff0c;之前我们在mysql专栏 也有提到过&#xff0c;这边就不再过多的赘述&#xff0c;忘记了的小伙伴可以再次阅读这篇文章 终于明白了数据库的【关系型】与【非关系型】 其实这还是挺重要的&#xff…

ruoyi+vue回显数字的问题,解决方案

在项目中用ruoyi框架和前端vue进行开发&#xff0c; 需求是在前端生成下拉框&#xff0c;下拉框中的内容需要调用后端接口进行数据返回&#xff0c; 现在新增的时候&#xff0c;数据已经返回了&#xff0c;但是再修改的时候&#xff0c;进行回显数据导致前端列表中展示出来的…

城市排水监测系统为城市排水防涝提质增效

城市化进程中&#xff0c;城市排水系统成为城市基础设施建设的重要组成部分。然而&#xff0c;随着气候变化和城市建设规模的扩大&#xff0c;极端天气和内涝风险不断增加&#xff0c;城市的排水系统面临巨大挑战。因此&#xff0c;建立一套智能化城市排水监测系统&#xff0c;…

【python】一些常用的pandas技巧

有了gpt之后&#xff0c;确实很多代码都可以让gpt给改错。嘎嘎香 merge多个dateframe https://stackoverflow.com/questions/44327999/how-to-merge-multiple-dataframes data_net [a,b,c,d] net_merged reduce(lambda left,right: pd.merge(left,right,on[key column],ho…

小程序安全指南:保护用户数据的最佳实践

第一章&#xff1a;引言 近年来&#xff0c;小程序已成为移动应用开发的重要组成部分。它们为用户提供了方便的功能和个性化的体验&#xff0c;然而&#xff0c;与此同时&#xff0c;小程序安全问题也引起了广泛的关注。保护用户数据是开发者应该高度重视的问题。在本指南中&a…

JavaScript ES11新特性

文章目录 导文可选链操作符&#xff08;Optional Chaining Operator&#xff09;空值合并操作符&#xff08;Nullish Coalescing Operator&#xff09;动态 import() 函数BigInt 类型Promise.allSettled() 导文 JavaScript ES11&#xff0c;也被称为ES2020&#xff0c;引入了一…

经纬度、时差知识整理(理解与应用)

经纬度是经度与纬度的合称组成一个坐标系统&#xff0c;称为地理坐标系统&#xff0c;它是一种利用三度空间的球面来定义地球上的空间的球面坐标系统&#xff0c;能够标示地球上的任何一个位置。初一的同学在学地理这门课的时候&#xff0c;一上来很快就会学到经纬度这个概念。…