c语言进阶部分详解(指针初阶)

news2024/11/25 5:15:08

大家好!,前段时间一直在准备数学建模竞赛,现在也是忙完了。抓紧继续给大家带来c语言的内容。今天给大家带来指针初阶部分的讲解

当我们谈论C语言中的指针时,实际上是在讨论一种非常重要的概念,因为指针是C语言的核心之一。它们允许我们直接访问内存中的数据,这在编写高效和灵活的程序时非常有用。让我们来深入了解一下指针的概念和用法


目录

一.指针是什么 

1.指针的初步理解

 2.指针的大小

3.总结

二.指针和指针类型

 三.指针类型的意义

 1.指针+-整数

2.解引用 

四.野指针

1.野指针成因

①指针未初始化

②指针越界访问 

​编辑

③指针指向的空间释放 

五.指针运算

1.指针+-整数

 2.指针-指针

 3.指针的关系运算

 4.注意

六.指针和数组

七.二级指针 

八.指针数组


 

一.指针是什么 

1.指针的初步理解

  指针理解的2个要点:
1. 指针是内存中一个最小单元的编号,也就是地址
2. 平时口语中说的指针,通常指的是指针变量,是用来存放内存地址的变量 
 
总结:指针就是地址,口语中说的指针通常指的是指针变量
内存示意图:
指针变量:
我们可以通过 & (取地址操作符)取出变量的内存其实地址,把地址可以存放到一个变量中,这个变量就是指针变量
#include<stdio.h>
int main()
{
	int a = 7;//创建变量时,在内存里开辟的一篇空间
	int* pa = &a;//这里我们对变量a,取出它的地址,可以使用&操作符
	//a变量占用4个字节的空间,这里是将a的4个字节的第一个字节的地址存放在p变量
	//中,p就是一个之指针变量
	return 0;
}

总结:指针变量,用来存放地址的变量。(存放在指针中的值都被当成地址处理) 


 2.指针的大小

在C语言中,指针的大小是根据计算机体系结构和操作系统的不同而变化的。通常情况下,指针的大小与计算机的位数相关。在32位系统中,指针的大小通常是4字节(32位),而在64位系统中,指针的大小通常是8字节(64位)

3.总结

  • 指针是用来存放地址的,地址是唯一标示一块地址空间的。
  • 指针的大小在32位平台是4个字节,在64位平台是8个字节

二.指针和指针类型

变量有不同的类型,整形,浮点型等。那指针有没有类型呢?

指针确实有:

char  *pc = NULL;
int   *pi = NULL;
short *ps = NULL;
long  *pl = NULL;
float *pf = NULL;
double *pd = NULL;
这里可以看到,指针的定义方式是: type + *
其实:
char* 类型的指针是为了存放 char 类型变量的地址。
short* 类型的指针是为了存放 short 类型变量的地址。
int* 类型的指针是为了存放 int 类型变量的地址

 接下来探求指针类型的意义


 三.指针类型的意义

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

比如: char* 的指针解引用就只能访问一个字节,而 int* 的指针的解引用就能访问四个字节 

 1.指针+-整数

int main()
{
	int n = 10;
	char* pc = (char*)&n;
	int* pi = &n;

	printf("%p\n", &n);
	printf("%p\n", pc);
	printf("%p\n", pc + 1);
	printf("%p\n", pi);
	printf("%p\n", pi + 1);
	return 0;
}

2.解引用 

 可以看到pc与pi的数值均是相等的,当运行完*pc=0后,只是改变了第一个字节的数值。

当运行完*p=0后,只是改变四个字节的数值


四.野指针

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

1.野指针成因

①指针未初始化

int main()
{
	int* pa;
	*pa = 10;
	return 0;
}

连编译器都会阻止我们使用未初始化的指针

指针越界访问 

int main()
{
	int arr[10] = { 0 };
	int* p = arr;
	for (int i = 0; i <= 11; i++)
	{
		*(p++) = i;
	}
	return 0;
}

当指针指向的范围超出数组arr的范围时,p就是野指针: 自然也会报错

指针指向的空间释放 

int* createInt() {
    int num = 5;
    int* ptr = &num;
    return ptr;
}

int main() {
    int* ptr = createInt();
    printf("%d\n", *ptr);  // 输出5,但是这是不安全的操作

    // 在这之后,ptr成为了野指针,因为它指向的内存空间已经被释放

    printf("%d\n", *ptr);  // 未定义的行为,可能输出垃圾值或导致程序崩溃

    return 0;
}

在上面的示例中,函数createInt()创建了一个整型变量num,并将其地址赋给指针ptr,然后返回了该指针。在main()函数中,我们打印了指针ptr所指向的值,输出结果为5。但是在createInt()函数结束后,变量num的生命周期结束,其所占用的内存空间被释放。此时,指针ptr仍然保留着之前的内存地址,成为了野指针。在后续的打印操作中,我们试图访问野指针ptr所指向的值,这是不安全的操作,可能导致程序出现未定义的行为 


 

五.指针运算

1.指针+-整数

  • 指针加减整数是指对指针进行加减运算,其中整数表示要加减的偏移量。这种操作通常用于在指针上移动一定的距离,以便访问指针指向的内存位置
  • 指针的加减运算是基于指针所指向的数据类型的大小进行的。例如,如果一个指针指向一个int类型的变量,那么对该指针进行加1的操作,将使指针指向下一个int类型的变量。同样地,对指针进行减1的操作,将使指针指向前一个int类型的变量 
#include<stdio.h>
int main()
{
	int arr[] = { 1,2,3,4,5 };
	int* pa = arr;
	for (int i = 0; i < 5; i++)
	{
		printf("%d ", *(pa++));
	}
	return 0;
}

 

 2.指针-指针

指针-指针操作是指对两个指针进行减法运算,得到它们之间的偏移量。这种操作通常用于计算两个指针之间的距离或元素的个数 

接下来我们可以利用这一点来模拟实现strlen()函数

int my_strlen(char* pa)
{
	char* start = pa;
	while (*pa)
	{
		pa++;
	}
	return pa - start;
}

int main()
{
	char arr[] = "hello";
	printf("%d", my_strlen(arr));
	return 0;
}

 

 3.指针的关系运算

  • ==:判断两个指针是否相等。如果两个指针指向同一个内存地址,则它们相等,返回1;否则返回0
  • !=:判断两个指针是否不相等。如果两个指针指向不同的内存地址,则它们不相等,返回1;否则返回0
  • >:判断一个指针是否大于另一个指针。指针的大小是根据指针所指向的内存地址来比较的。如果第一个指针指向的地址在第二个指针指向的地址之后,则第一个指针大于第二个指针,返回1;否则返回0
  • <:判断一个指针是否小于另一个指针。指针的大小是根据指针所指向的内存地址来比较的。如果第一个指针指向的地址在第二个指针指向的地址之前,则第一个指针小于第二个指针,返回1;否则返回0
  • >=:判断一个指针是否大于等于另一个指针。如果第一个指针大于第二个指针或两个指针相等,则返回1;否则返回0
  • <=:判断一个指针是否小于等于另一个指针。如果第一个指针小于第二个指针或两个指针相等,则返回1;否则返回0

 4.注意

允许指向数组元素的指针与指向数组最后一个元素后面的那个内存位置的指针比较,但是不允许与指向第一个元素之前的那个内存位置的指针进行比较


六.指针和数组

1.指针是一个变量,用于存储内存地址。指针变量可以指向任何类型的数据,包括数组。通过指针,我们可以间接地访问和操作内存中的数据。
2.数组就是数组,可以存放一组数,数组的大小是取决于元素的类型和个数。
3.数组的数组名是数组首元素的地址,地址是可以放在指针变量中的。通过指针可以访问一个数组的元素 

  • 数组名和指针:在C语言中,数组名可以被看作是一个指向数组首元素的指针。例如,对于数组int arr[5]arr可以被视为指向arr[0]的指针。因此,可以通过指针来访问数组中的元素,例如*arr表示数组的第一个元素,*(arr + 1)表示数组的第二个元素。
  • 此外,指针算术运算也可以应用于数组名。例如,arr + 1表示数组的第二个元素的地址,arr + 2表示数组的第三个元素的地址。这是因为数组的元素在内存中是连续存储的
int main()
{
	int arr[] = { 1,2 };
	int* pa = arr;
	printf("%p\n", arr);
	printf("%p\n", &arr[0]);
	return 0;
}

 

可见数组名通常是表示数组首元素的地址,但是有两个例外:
1.sizeof(数组名),数组名单独放在sizeof内部,数组名表示整个数组,计算的是数组的大小,单位是字节。
2.&数组名,数组名表示整个数组,取出的是数组的地址,数组的地址和数组首元素的地址是一样的,但是类型和意义是不一样的


 

七.二级指针
 

指针变量也是变量,是变量就有地址,那指针变量的地址存放在哪里?
这就是 二级指针 

int main()
{
	int a = 10;
	int* pa = &a;//一级指针
	int** ppa = &pa;//二级指针
	printf("%d\n", a);
	**ppa = 0;//通过两次解引用来改变值
	printf("%d\n", a);
	return 0;
}

 


八.指针数组

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

可以使用指针数组,模拟一个二维数组 

int main()
{
	int arr1[] = { 1,2,4,6 };
	int arr2[] = { 7,2,4,4 };
	int arr3[] = { 1,2,9,6 };

	int* p[] = { arr1,arr2,arr3 };

	for (int i = 0; i < 3; i++)
	{
		for (int j = 0; j < 4; j++)
		{
			printf("%d ", p[i][j]);
		}
		printf("\n");
	}
	return 0;
}

 


指针是C语言中一个强大而复杂的概念。通过使用指针,我们可以直接访问和修改内存中的数据,实现灵活和高效的内存操作。然而,在使用指针时需要小心,避免出现空指针和野指针的问题。希望这篇文章对你理解C语言中的指针部分有所帮助。

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

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

相关文章

《昆明海晏村:修缮后的新生,历史与现代的完美交融》

在昆明市的东南角&#xff0c;有一处名为海晏村的地方&#xff0c;这里曾是滇池北岸的重要码头&#xff0c;也是滇池文化的发源地之一。近年来&#xff0c;海晏村经过精心修缮&#xff0c;焕发出新的生机&#xff0c;成为了一个集历史、文化、艺术于一体的旅游胜地。那么&#…

Harp:面向跨空间域的分布式事务优化算法

Harp&#xff1a;面向跨空间域的分布式事务优化算法 庄琪钰1,2&#xff0c;李彤1,2&#xff0c;卢卫1,2, 杜小勇1,2 1 中国人民大学信息学院&#xff0c;北京 100872 2 数据工程与知识工程教育部重点实验室&#xff0c;北京 100872 摘要&#xff1a;近数据计算范式驱动了银行、…

whee: 美图秀秀出品AI绘画图片创作工具平台

【 产品介绍】 whee.com还提供了风格模型训练和创作词库的功能&#xff0c;让用户可以定制自己的专属风格和词汇。whee.com是一个适合各种水平和兴趣的用户的创意平台&#xff0c;无论是想要学习绘画&#xff0c;还是想要展示自己的才华&#xff0c;都可以在whee.com找到乐趣和…

openpnp - 给.openpnp2目录减肥

文章目录 openpnp - 给.openpnp2目录减肥概述笔记不会引起.openpnp2目录size持续增加的目录/文件列表会引起.openpnp2目录size持续增加的目录/文件列表可以做一个程序来给openpnp减肥END openpnp - 给.openpnp2目录减肥 概述 听同学说, 如果.openpnp2将磁盘分区都占满后, 就会…

【word日常操作】word里面表格已经设置了重复标题行,但是显示无效怎么办

在制作表格的过程当中&#xff0c;相信很多人都知道&#xff0c;表格不只有一页的时候就会在下一面&#xff0c;也会显示出来&#xff0c;然而这时我们需要让word表头重复出现&#xff0c;那么该怎么办呢? 1 出现问题 word表格如何设置多页时能重复表头&#xff0c;百度后出…

ElasticSearch系列-索引原理与数据读写流程详解

索引原理 倒排索引 倒排索引&#xff08;Inverted Index&#xff09;也叫反向索引&#xff0c;有反向索引必有正向索引。通俗地来讲&#xff0c;正向索引是通过key找value&#xff0c;反向索引则是通过value找key。ES底层在检索时底层使用的就是倒排索引。 索引模型 现有索…

01- 从零开始完整实现-循环神经网络RNN

一 简介 使用 pytorch 搭建循环神经网络RNN&#xff0c;循环神经网络&#xff08;Recurrent Neural Network&#xff0c;RNN&#xff09;是一类用于 处理序列数据的神经网络架构。与传统神经网络不同&#xff0c;RNN 具有内部循环结构&#xff0c;可以在处理序列数据时保持状态…

Qwen7b微调保姆级教程

前方干货预警&#xff1a;这可能是你能够找到的&#xff0c;最容易理解&#xff0c;最容易跑通的&#xff0c;适用于各种开源LLM模型的&#xff0c;同时支持多轮和单轮对话数据集的大模型高效微调范例。 我们构造了一个修改大模型自我认知的3轮对话的玩具数据集&#xff0c;使用…

HONEYWELL 05704-A-0145 工控控制模块

HONEYWELL 05704-A-0145 工控控制模块&#xff08;Industrial Control Module&#xff09;是工业自动化领域中的一种关键组件&#xff0c;用于控制和监测各种工业过程和设备。这些模块具有多种特点和功能&#xff0c;以下是一些通常与HONEYWELL 05704-A-0145 工控控制模块相关的…

态路小课堂丨光纤跳线的使用与维护小指南

点击蓝字 | 关注我们 TARLUZ态路 在光通信领域中&#xff0c;光纤跳线扮演着至关重要的角色。它作为一种用于连接光纤设备之间的光纤连接线&#xff0c;可以根据实际需求进行定制&#xff0c;以此来满足不同网络拓扑和连接方式的要求。在安装光纤跳线时&#xff0c;遇到的问题…

3ds max文件打包?max插件CG Magic一键打包整起!

3ds max文件如何打包&#xff1f;这个问题&#xff0c;小编听到不少网友的提问&#xff01; 今天CG Magic小编来和大家聊聊&#xff0c;文件更高效的操作&#xff0c;如何打包处理呢&#xff1f; 3DMAX这款软件的受众群体是比较高的&#xff0c;在工作方便的同时&#xff0c;…

Qt ---进程间的通信

进程间通讯方式Qt 提供了四种进程间通信的方式&#xff1a; 使用共享内存&#xff08;shared memory&#xff09;交互&#xff1a;这是Qt 提供的一种各个平台均有支持的进程间交互的方式。TCP/IP&#xff1a;其基本思想就是将同一机器上面的两个进程一个当做服务器&#xff0c…

24考研王道408数据结构-第三章“栈、队列、数组”课后算法题(P70--栈的模拟)

第三题 #include<iostream> using namespace std;bool solution(char s[]){int n8;int numI0;for(int i0;i<n;i){if(s[i]I){numI;}if(s[i]O){if(numI0){return false;}numI--;}}return true; }int main(){//char s[8]{I,O,I,I,O,I,O,O};char s[8]{I,O,O,I,O,I,I,O};if…

电压放大器的应用范围有哪些

电压放大器是一种常见的电子设备&#xff0c;用于将输入信号的电压放大到更高的水平。它在各个领域中具有广泛的应用范围。本文将详细介绍电压放大器的应用。 音频放大器&#xff1a; 电压放大器在音频系统中起着重要作用&#xff0c;用于将来自音源&#xff08;如CD播放器、MP…

Mybatis 动态语言 - mybatis-thymeleaf

前面我们介绍了Mybatis动态SQL的使用&#xff1b;本篇我们介绍使用mybatis-thymeleaf动态语言生成动态SQL。 如果您对Mybatis动态SQL不太了解&#xff0c;建议您先进行了解后再阅读本篇&#xff0c;可以参考&#xff1a; Mybatis 动态SQL – 使用if,where标签动态生成条件语句…

为什么有人会先考二建再考一建?

因为时间&#xff0c;因为难度&#xff0c;因为需求。 首先说时间&#xff0c;考二建比考一建的限制少很多&#xff0c;很多人入职没多久&#xff0c;研究生甚至在大学就能考了。本着早考早有证&#xff0c;早考早赚钱的原则&#xff0c;很多人会选择先考二建。 再说难度&…

Jmeter —— 常用的几种断言方法(基本用法)

在使用JMeter进行性能测试或者接口自动化测试工作中&#xff0c;经常会用到的一个功能&#xff0c;就是断言&#xff0c;断言相当于检查点&#xff0c;它是用来判断系统返回的响应结果是否正确&#xff0c;以此帮我们判断测试是否通过&#xff0c;本文 主要介绍几种常用的断言&…

【Spring使用三级缓存解决循环依赖的过程】

testService1和testService2相互依赖 当Spring创建testService1对象时&#xff0c;它会先从一级缓存中查找是否存在testService1的实例。如果缓存中不存在testService1实例&#xff0c;它将继续查找二级缓存中是否存在testService1。如果二级缓存中也不存在testService1实例&…

GDAL+Java实现获取对应栅格影像经纬度对应的像素值

从前面的GDAL系列博文中&#xff0c;可以指导GDAL可以将栅格影像文件读出为对应的多维数组&#xff0c;可以读出每一个像素格对应的像素值。但如何根据经纬度直接读取像素值呢&#xff1f;博主从查阅了网上的相关文档&#xff0c;发现有个人写的计算公式是错误的&#xff0c;用…

日期类完善

目录 日期类&#xff1a; 运算符重载&#xff1a; ​编辑 赋值重载&#xff1a; 拷贝构造和赋值重载的区别&#xff1a; 实现赋值重载&#xff1a; 划分成员函数&#xff1a; 日期类的声明和定义分离 日期类-&#xff1a; 日期类- 前置后置 日期类&#xff1a; 写一个简…