C语言:指针详解

目录

一、内存与地址

二、指针变量

2.1指针变量

2.2解引用操作符(*)

2.3 指针变量的大小

三、指针运算

3.1指针+(-)整数

3.2指针-指针

 ​编辑

3.3指针的关系运算 

四、野指针

4.1指针未初始化

4.2指针越界

​编辑

4.3指针指向的空间已经释放

4.4NULL

五、指针传值调用与传址调用

5.1传值调用

5.2传址调用

七、一维数组的传参

八、二维数组的传参

九、二级指针

9.1概念

9.2二级指针的使用

十、指针数组

十、回调函数


一、内存与地址

在购买电脑时,常常可以看到电脑的内存为8GB/16GB/32GB等,为了可以有效的管理内存,就把内存分成一个个的内存单元,每个内存单元的大小是1个字节。

bit    比特位
byet   字节 1 byte= 8 bit
KB 1 KB= 1024 byte
MB 1 MB= 1024 KB
GM 1 GB= 1024 MB
TB 1 TB= 1024 GB
PB 1 PB= 1024 TB

 每个内存单元都有编号,CPU就是通过内存单元的编号找到相对应的内存空间。

计算机中内存单元的编号就是地址,在C语言中地址就叫做指针。

                                         内存单元的编号==地址==指针

二、指针变量

2.1指针变量

在C语言中,通过&操作符可以得到一个地址,为了方便的使用这个地址,可以将该地址存储到指针变量中。

#include
int main()
{
    int a=1;
    int *P=&a;//将a的地址存储到p中
    return 0;
}

2.2解引用操作符(*)

  将地址储存在指针里后,就可以用解引用操作符(*),通过指针(地址)找到指针(地址)所指向的对象。

#include
int main()
{
	int a = 0;
	int* p = &a;
	*p = 1;//通过*找到a,并更改a的值
	printf("%d", a);
	return 0;
}

C语言:指针详解_第1张图片

2.3 指针变量的大小

指针变量的大小取决与地址的大小,不管储存的是什么类型的变量。

在32位平台下就是4个字节。

在64位平台下就是8个字节。

我所用的编译器在X64的环境下就是64位平台

X86的环境下就是32位平台

C语言:指针详解_第2张图片

C语言:指针详解_第3张图片

由上面两幅图可以清楚的看到,无论是上面类型的指针,指针的大小只取决与地址的大小。 

三、指针运算

因为数组在内存中是连续存放的,所以知道首元素的地址,就可以找到所以元素的地址。

3.1指针+(-)整数

#include
int main()
{
	int arr[10] = { 1,2,3,4,5,6,7,8,9,10 };
	int* p = &arr[0];
	//指针加法打印
	for (int i = 0; i < 10; i++)
	{
		printf("%d\n", *(p + i));
	}
	//将指针调整到arr[9]的位置
	p = p + 9;
	//指针减法打印
	for (int i = 9; i >= 0; i--)
	{
		printf("%d\n", *(p - i));
	}
	return 0;
}

C语言:指针详解_第4张图片

3.2指针-指针

#include
int main()
{
	int arr[10] = { 1,2,3,4,5,6,7,8,9,10 };
	int* p = &arr[0];
	int* x = &arr[5];
	int a=x - p;
	printf("%d", a);
	return 0;
}

 C语言:指针详解_第5张图片

3.3指针的关系运算 

#include 
int main()
{
	int arr[10] = { 1,2,3,4,5,6,7,8,9,10 };
	int* p = &arr[0];
	int i = 0;
	int sz = sizeof(arr) / sizeof(arr[0]);
	while (p < arr + sz) //指针的⼤⼩⽐较
	{
		printf("%d ", *p);
		p++;
	}
	return 0;
}

C语言:指针详解_第6张图片

四、野指针

定义:指针指向的位置是不确定的或随机的。

4.1指针未初始化

#include
int main()
{
    int* p;//指针未初始化
    p = 20;
    return 0;
}

4.2指针越界

#include
int main()
{
	int a[5] = { 0 };
	int* p = &a;
	for (int i = 0; i < 10; i++)
	{
		*p++ = 2;//p访问的范围超过了数组的大小,超过部分即为野指针
	}
	return 0;
}

C语言:指针详解_第7张图片

4.3指针指向的空间已经释放

#include 
int* test()
{
	int n = 100;
	return &n;
}
int main()
{
	int* p = test();//test的空间已经释放
	printf("%d\n", *p);
	return 0;
}

4.4NULL

当指针变量使用完成后,可以将其设为空指针(NULL)。在C语言中,如果一个指针的内容为NULL,就不会再取访问指针。

#include
int main()
{
	int arr[10] = { 1,2,3,4,5,6,7,8,9,10 };
	int* p = &arr[0];
	for (int i = 0; i < 10; i++)
	{
		*(p++) = i;
	}
	//此时p已经越界了,可以把p置为NULL
	p = NULL;
	//下次使⽤的时候,判断p不为NULL的时候再使⽤
	//...
	p = &arr[0];//重新让p获得地址
	if (p != NULL) //判断
	{
		//...
	}
	return 0;
}

五、指针传值调用与传址调用

5.1传值调用

传值调用:函数在使用时,根据参数内容创建临时变量完成函数。

创建的临时变量的修改并不会改变参数的值。

#include 
void Swap1(int x, int y)
{
	int tmp = x;
	x = y;
	y = tmp;
}
int main()
{
	int a = 0;
	int b = 0;
	scanf("%d %d", &a, &b);
	printf("交换前:a=%d b=%d\n", a, b);
	Swap1(a, b);
	printf("交换后:a=%d b=%d\n", a, b);
	return 0;
}

C语言:指针详解_第8张图片

5.2传址调用

传址调用:函数在使用时,找到参数的地址,用参数完成函数。

#include 
void Swap2(int* px, int* py)
{
	int tmp = 0;
	tmp = *px;
	*px = *py;
	*py = tmp;
}
int main()
{
	int a = 0;
	int b = 0;
	scanf("%d %d", &a, &b);
	printf("交换前:a=%d b=%d\n", a, b);
	Swap2(&a, &b);
	printf("交换后:a=%d b=%d\n", a, b);
	return 0;
}

C语言:指针详解_第9张图片

七、一维数组的传参

本质:传递数组首元素的地址

#include 
void test(int arr[])
{
	int sz2 = sizeof(arr);
	printf("sz2 = %d\n", sz2);
}
int main()
{
	int arr[10] = { 1,2,3,4,5,6,7,8,9,10 };
	int sz1 = sizeof(arr);//计算数组的字节大小
	printf("sz1 = %d\n", sz1);
	test(arr);//传的是首元素的地址,所以字节大小大小永远为4/8
	return 0;
}

C语言:指针详解_第10张图片

八、二维数组的传参

本质:⼆维数组传参本质上也是传递了地址,传递的是第一⾏这个⼀维数组的地址。
#include 
void test(int(*p)[5], int r, int c)
{
	int i = 0;
	int j = 0;
	for (i = 0; i < r; i++)
	{
		for (j = 0; j < c; j++)
		{
			printf("%d ", *(*(p + i) + j));
		}
		printf("\n");
	}
}
int main()
{
	int arr[3][5] = { {1,2,3,4,5}, {2,3,4,5,6},{3,4,5,6,7} };
	test(arr, 3, 5);
	return 0;
}

 C语言:指针详解_第11张图片

九、二级指针

9.1概念

指针变量也是变量,也有它自己的地址。指向指针的指针就是二级指针。

C语言:指针详解_第12张图片

 上面的图片中,ppa就是二级指针,它指向了pa这个指针。

9.2二级指针的使用

对ppa使用解引用操作符(*),访问的就是pa的地址

如果连续使用两个*,访问的就是a的地址。

#include
int main()
{
	int a = 10;
	int* pa = &a;
	int** ppa = &pa;
	**ppa = 30;//找到a
	printf("%d\n", a);
	*ppa =0x27849912;//找到pa
	printf("%p", pa);
	return 0;
}

 C语言:指针详解_第13张图片

十、指针数组

指针数组:存放指针的数组 。

指针数组中每一个数都是指针。

#include
int main()
{
	int* arr[5];
	return 0;
}

十、回调函数

回调函数:通过函数指针调用的函数。
如果你把函数的指针(地址)作为参数传递给另⼀个函数,当这个指针被⽤来调⽤其所指向的函数
时,被调⽤的函数就是回调函数。回调函数不是由该函数的实现⽅直接调⽤,⽽是在特定的事件或条 件发⽣时由另外的⼀⽅调⽤的,⽤于对该事件或条件进⾏响应。
void calc(int(*pf)(int, int))
{
 int ret = 0;
 int x, y;
 printf("输⼊操作数:");
 scanf("%d %d", &x, &y);
 ret = pf(x, y);
 printf("ret = %d\n", ret);
}

C语言:指针详解_第14张图片

可以留个免费的赞吗?

你可能感兴趣的:(C语言知识,c语言,开发语言)