C语言指针详解(上)

文章目录:

1.指针是什么?

2.指针和指针类型

2.1指针的解引用

 2.2指针±整数

3.野指针

 3.1野指针成因

3.2如何规避野指针

 4.指针运算

4.1指针±整数

4.2指针-指针

 4.3指针的关系运算

5.指针和数组

6.二级指针

7.指针数组


1.指针是什么?

指针是内存中一个最小单元的编号,也就是地址
平时口语中说的指针,通常指的是指针变量,是用来存放内存地址的变量

我们通过图片来理解这句话:

 总结:指针就是地址,口语中说的指针通常指的是指针变量

我们再来了解一下指针变量的概念:

我们可以通过 & (取地址操作符)取出变量的内存其实地址,把地址可以存放到一个变量中,这个变量就是指针变量。

看代码:

#include <stdio.h>
int main()
{
 int a = 10;//在内存中开辟一块空间
 int *p = &a;//使用&操作符取出变量a的地址。
//a变量占用4个字节的空间,这里是将a的4个字节的第一个字节的地址存放在p变量中,p就是一个之指针变量。
 return 0;
}

总结

指针变量,用来存放地址的变量。(存放在指针中的值都被当成地址处理)。
经过仔细的计算和权衡我们发现一个字节给一个对应的地址是比较合适的。
对于 32 位的机器,假设有 32 根地址线,那么假设每根地址线在寻址的时候产生高电平(高电压)和低电平(低电压)就是( 1 或者 0 );
那么 32 根地址线产生的地址就会是:
00000000 00000000 00000000 00000000
00000000 00000000 00000000 00000001
...
11111111 11111111 11111111 11111111
这里就有 2 32 次方个地址。
每个地址标识一个字节,那我们就可以给 2^32Byte == 2^32/1024KB ==
2^32/1024/1024MB==2^32/1024/1024/1024GB == 4GB 4G 的空间进行编址。
同样的方法,那 64 位机器,就是给 64根地址线,就是2^32*4GB的空间
32 位的机器上,地址是 32 0 或者 1 组成二进制序列,那地址就得用 4 个字节的空间来存储,所以一个指针变量的大小就应该是 4 个字节。
那如果在 64 位机器上,如果有 64 个地址线,那一个指针变量的大小是 8 个字节,才能存放一个地址

 

 总结:

指针变量是用来存放地址的,地址是唯一标示一个内存单元的。
指针的大小在32位平台是4个字节,在64位平台是8个字节。

2.指针和指针类型

指针的定义方式是:type + *,例如:        

int* 类型的指针是为了存放 int 类型变量的地址。

short* 类型的指针是为了存放 short 类型变量的地址。

char* 类型的指针是为了存放 char 类型变量的地址。
double*类型的指针是为了存放 duoble 类型变量的地址。

那么指针类型的意义是什么呢? 

2.1指针的解引用

下面我们有图有真相:

通过两图对比我们发现:指针类型的决定了:指针在进行解引用操作时访问几个字节(权限)。

int* 类型的指针在解引用时访问4个字节;

shot* 类型的指针在解引用时访问2个字节;

char* 类型的指针在解引用时访问1个字节;

double* 类型的指针在解引用时访问4个字节;

 2.2指针±整数

这里举了指针+整数的栗子,- 整数也是一样的,只不过是往低地址走。

在这里的指针类型决定了指针的步长(向前/向后走一步有多大距离)。

int*指针 +1,意思是跳过一个整型的大小,也就是向后走4个字节;

short*指针 +1,意思是跳过一个短整型的大小,也就是向后走2个字节;

char*指针 +1,意思是跳过一个字符的大小,也就是向后走1个字节;

double*指针 +1,意思是跳过一个浮点型的大小,也就是向后走8个字节;

总结:

指针的类型决定了,对指针解引用的时候有多大的权限(能操作几个字节)。

指针的类型决定了指针向前或者向后走一步有多大(距离)。

3.野指针

概念: 野指针就是指针指向的位置是不可知的(随机的、不正确的、没有明确限制的)

 3.1野指针成因

1.指针未初始化

#include <stdio.h>
int main()
{
	int* p;//局部变量指针未初始化,默认为随机值
	*p = 20;//此时p改动的不是想要的目标地址
	return 0;
}

2.指针越界访问

#include<stdio.h>
int main()
{
	int arr[10] = { 0 };
	int* p = arr;
	int sz = sizeof(arr) / sizeof(arr[0]);
	int i = 0;
	for (i = 0; i <= sz; i++)//当i=sz时发生数组越界访问
	{
		*p = i;
		p++;
	}
	return 0;
}

3.指针指向的空间释放

#include<stdio.h>
int* test()
{
	int num = 100;
	return &num;
}
int main()
{
	int* p = test();
	*p = 200;
	return 0;
}
//此时p为野指针,因为函数调用后空间会被系统回收,此时num的地址被回收,p改动的不是想要的目标地址

3.2如何规避野指针

1. 指针初始化
2. 小心指针越界
3. 指针指向空间释放,及时置 NULL
4. 避免返回局部变量(栈空间)的地址
5. 指针使用之前检查有效性

指针初始化

#include<stdio.h>
int main()
{
	int a = 10;
	int* pa = &a;//明确初始化
	//NULL--0,就是初始化指针的
	int* p = NULL;
	return 0;
}

 检查指针有效性

#include<stdio.h>
int main()
{
	int a = 10;
	int* p = NULL;
	//*p = 20;//无法改变
    //空指针的指针变量是不能改值的

	if (p != NULL)//验证
	{
		printf("%d\n", *p);
	}
	return 0;
}

 4.指针运算

4.1指针±整数

#define N_VALUES 5
float values[N_VALUES];
float* vp;
//指针±整数;指针的关系运算
int main()
{
	for (vp = &values[N_VALUES - 1]; vp >= &values[0]; vp--)
	{
		*vp = 1;
	}
	return 0;
}

图解:

4.2指针-指针

我们来举个栗子,用指针-指针的方法模拟实现库函数strlen

//模拟实现strlrn
#include<stdio.h>
int my_strlen(char* arr)
{
	char* start = arr;
	while (*arr)
	{
		arr++;
	}
	return arr - start;
}
int main()
{
	char arr[] = "cjcwqr";
	int len = my_strlen(arr);
	printf("%d\n", len);
	return 0;
}

注意:

1.两个指针相减的前提是:指针指向同一块儿连续的空间

2.指针类型不同不能相减

 4.3指针的关系运算

我们先来看两段代码和他们的逻辑:

#define N_VALUES 5
float values[N_VALUES];
float* vp;
int main()
{
	for (vp = &values[N_VALUES]; vp > &values[0];)
	{
		*--vp = 0;
	}
	return 0;
}

图解:

#define N_VALUES 5
float values[N_VALUES];
float* vp;
int main()
{
	for (vp = &values[N_VALUES - 1]; vp >= &values[0]; vp--)
	{
		*vp = 0;
	}
	return 0;
}

 图解:

 两段代码一个是访问数组前的地址,一个是访问后的地址,实际上都是可以顺利执行功能的,但我们还是应该避免第二种写法,因为标准并不保证它可行。

标准规定:

允许指向数组元素的指针与指向数组最后一个元素后面的那个内存位置的指针比较,

但是不允许与指向第一个元素之前的那个内存位置的指针进行比较。

5.指针和数组

我们知道了数组名就是数组首元素的地址(两种特殊情况),那我们就可以使用指针来访问一个数组,比如:

#include <stdio.h>
int main()
{
	int arr[10] = { 1,2,3,4,5,6,7,8,9,10 };
	int* pa = arr;
	int i = 0;
	for (i = 0; i < 10; i++)
	{
		//方法一
		//printf("%d ", *(pa + i));
		//方法二
		printf("%d ", *pa);
		pa++;
	}
	return 0;
}//输出1 2 3 4 5 6 7 8 9 10

6.二级指针

我们还是通过图解来观察理解二级指针:

 前面我们知道了指针变量是用来存放指针的地址的,那么指针变量的地址应该存到哪里呢?

这就需要用到二级指针了

通过**pp对pp中的地址解引用,找到的是p,**pp访问的就是p,再通过*p对p中的地址解引用,找到的就是a ,*p访问的就是a。

7.指针数组

首先我来问个问题,指针数组是指针呢还是数组呢?

指针数组是数组,是个存放指针的数组。

 我们通过用指针数组来模拟二维数组来对其进行讲解 :
 

//用一维数组模拟一个二维数组
#include<stdio.h>
int main()
{
	int arr1[] = { 1,2,3,4,5 };
	int arr2[] = { 2,3,4,5,6 };
	int arr3[] = { 3,4,5,6,7 };
	int arr4[] = { 4,5,6,7,8 };
	int* arr[] = { arr1,arr2,arr3,arr4 };
	int i = 0;
    //方法一
	//for (i = 0; i < 4; i++)
	//{
	//	int j = 0;
	//	for (j = 0; j < 5; j++)
	//	{
	//		printf("%d ", *(*(arr + i) + j));
	//	}
	//	printf("\n");
	//}
    //方法二
	for (i = 0; i < 4; i++)
	{
		int j = 0;
		for (j = 0; j < 5; j++)
		{
			printf("%d ",arr[i][j]);
		}
		printf("\n");
	}
	return 0;
}

我们知道数组名就是首元素的地址(两个例外) ,这里创建的指针数组int* arr[ ]存放的就是每个数组首元素的地址,我们进行循环首先通过arr[i]找到每个数组,再通过arr[i][j]来访问数组中的每个元素,另一种方法也是同理,先通过*(arr+i)找到每个数组,再通过*(*(arr + i) + j)来访问数组中的每个元素,以达到实现模拟二维数组的效果。

好了以上就是今天的全部内容了,对友友们有帮助的话不妨三连加关注走一波,后期会持续更新C语言干货!

  • 2
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 1
    评论
### 回答1: "C语言指针详解.pdf" 是一份详细介绍C语言指针概念和使用的PDF文档。C语言中,指针是一种特殊的变量类型,用于存储其他变量的内存地址。 该PDF文档首先详细介绍了指针的定义和声明。指针的声明需要指定指针变量的类型和名称,并使用星号(*)来表示该变量是一个指针指针变量名的前面加上一个星号,可以获取所指向的变量的值,这被称为"解引用"。 文档还介绍了指针的运算。指针可以进行自增和自减运算,指针之间可以进行相减操作,返回的结果表示它们之间的距离或者偏移量。此外,还可以将指针赋值给另一个指针,或者将指针赋值给一个变量,反之亦然。 除了基本的指针概念,文档还详细介绍了指针的常见应用场景。这包括指针作为函数参数,用于在函数内部对传入的变量进行修改。还有通过指针来实现动态内存分配和释放,以及使用指针实现数据结构(如链表和树)等。 此外,该文档还包含一些常见的指针错误和问题的解决方案。这些错误包括空指针引用、野指针引用以及内存泄漏等。文档指出了这些错误的影响以及如何避免它们。 总的来说,"C语言指针详解.pdf" 是一份详细介绍C语言指针概念、使用和常见问题解决方案的文档,对于学习和理解C语言指针的人们是一份宝贵的资料。 ### 回答2: 《C语言指针详解.pdf》是一本关于C语言指针的详细解析的电子书。在这本书中,作者详细介绍了C语言指针的概念、用途和基本语法。 首先,指针C语言中非常重要的概念,它是一种数据类型,用于存储和操作内存地址。指针可以指向各种数据类型,如整数、字符、数组和结构体等。 在《C语言指针详解.pdf》中,作者详细讲解了指针的声明和初始化,以及如何通过指针来访问和修改变量的值。作者还介绍了指针与数组的关系,以及指针和函数之间的关联。 此外,书中还涵盖了指针的高级应用,如指针的算术运算、指向指针指针指针数组等。作者通过丰富的例子和代码来帮助读者理解这些概念和技巧。 《C语言指针详解.pdf》不仅适合C语言初学者,也适合有一定编程基础的读者。通过阅读此书,读者将能够更深入地理解C语言指针的功能和用法,掌握指针在编程中的灵活运用。 总之,《C语言指针详解.pdf》是一本内容详尽且易于理解的C语言指针教程。读者通过阅读此书,可以提高自己在C语言编程中的指针应用能力,从而更好地实现程序的设计和开发。 ### 回答3: 《C语言指针详解.pdf》是一本介绍C语言指针概念和使用方法的详细手册。C语言中的指针是一种非常重要和特殊的数据类型,它提供了直接访问内存地址的能力,使得C语言具有了更高的灵活性和效率。 这本手册首先会介绍指针的基本概念,包括指针变量的定义和声明、指针的初始化和赋值。它会详细讲解指针和变量之间的关系,以及指针的运算规则和使用方法。读者可以学习到如何通过指针操作变量的值和地址,以及如何利用指针实现函数的参数传递和返回值。 接下来,手册会介绍指针和数组之间的关系。C语言中,数组名本质上是一个指向数组首元素的常量指针,因此可以通过指针来操作数组。手册将详细讲解指针和数组的指针算术运算,以及指针和多维数组的关系。 此外,手册还会介绍指针和字符串之间的关系。C语言中,字符串本质上是以空字符结尾的字符数组,可以通过指针来操作字符串。手册将详细讲解指针和字符串的操作,包括字符串的输入输出、字符串的比较和拷贝。 最后,手册还会介绍指针和结构体之间的关系。C语言中,结构体是用户自定义的复合数据类型,可以通过指针来操作结构体。手册将详细讲解指针和结构体的操作,包括结构体指针的定义和使用,以及结构体指针作为函数参数的传递方式。 总之,《C语言指针详解.pdf》是一本深入浅出的指针教程,对于想更深入理解C语言指针的读者来说,是一本非常实用的参考书。无论是初学者还是有一定基础的读者,都可以从中获得很多宝贵的知识和技巧。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

茉莉蜜茶v

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值