C 语言指针进阶

news2024/9/22 21:30:46

1.0 指针的定义

指针是内存中一个最小单元的编号(内存单元的编号称之为地址【地址就是指针指针就是地址】)指针通常是用来存放内存地址的一个变量。本质上指针就是地址:口语上说的指针起始是指针变量,指针变量就是一个变量,是一个用于存放地址的变量,指针指向的就是地址,通过这个地址可以找到对应的内存单元。

指针变量创建:

#define  _CRT_SECURE_NO_WARNINGS
#include "stdio.h"
#include "stdlib.h"
#include "math.h"
#include <string.h>
#include "add.h"
#include <stdint.h>

/*
****************************
*  DEF    :  指针    
*  参数   :  无参数
*  返回值 :  无返回值
*  时间   :  2024/7/14
*  作者   :  _沧浪之水_
****************************
*/

int main()
{
	// a 是一个整型变量,占用4个字节内存空间
	int a = 10;
	// pa 是一个指针变量,指针变量是用来存放地址的
	int* pa = &a;
	return 0;
}

总的来说,指针变量是用于存放地址的变量,(存放在指针中的值被当做是地址处理),在32位的平台下一个指针变量的大小是4个字节,在64位地址的机器上指针变量的大小是8个字节。

#define  _CRT_SECURE_NO_WARNINGS
#include "stdio.h"
#include "stdlib.h"
#include "math.h"
#include <string.h>
#include "add.h"
#include <stdint.h>

/*
****************************
*  DEF    :  指针    
*  参数   :  无参数
*  返回值 :  无返回值
*  时间   :  2024/7/14
*  作者   :  _沧浪之水_
****************************
*/

int main()
{
	char   *pc = NULL;
	short  *ps = NULL;
	int    *pi = NULL;
	double *pd = NULL;

	printf("%zu\n", sizeof(pc));
	printf("%zu\n", sizeof(ps));
	printf("%zu\n", sizeof(pi));
	printf("%zu\n", sizeof(pd));
	return 0;
}


2.0 指针与指针类型

指针类型的含义

1. 指针的类型决定的指针被解引用的时候被访问几个字节【所谓的解引用是官方的叫法,实际上就去获取地址当中的值,或者说是将地址当中的值取出来】,例如:int * 的指针,解引用访问4个字节,char * 的指针解引用是访问一个字节,推广到其他的参数时也是一样的。

#define  _CRT_SECURE_NO_WARNINGS
#include "stdio.h"
#include "stdlib.h"
#include "math.h"
#include <string.h>
#include "add.h"
#include <stdint.h>

/*
****************************
*  DEF    :  指针    
*  参数   :  无参数
*  返回值 :  无返回值
*  时间   :  2024/7/14
*  作者   :  _沧浪之水_
****************************
*/

int main()
{
	int a = 0x11223344;
	int* pa = &a;
	*pa = 0;

	char* pc = (char*)&a;
	*pc = 0;

	return 0;
}

2. 指针的步长:理解指针步长的意义

#define  _CRT_SECURE_NO_WARNINGS
#include "stdio.h"
#include "stdlib.h"
#include "math.h"
#include <string.h>
#include "add.h"
#include <stdint.h>

/*
****************************
*  DEF    :  指针    
*  参数   :  无参数
*  返回值 :  无返回值
*  时间   :  2024/7/14
*  作者   :  _沧浪之水_
****************************
*/

int main()
{
	int a = 0x11223344;
	int* pa = &a;
	char* pc = (char *) & a;

	printf("pa = %p\n", pa);
	printf("pa = %p\n", pa + 1);

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

指针类型决定了访问内存一次可以访问几个字节,如果是char * 的指针类型,那么访问内存只能一个字节一个字节的进行访问,如果是int * 类型的指针类型,那么访问内存就是以一次4个字节进行访问, int * pc如果是pc + 1 的话那么就是跳过前面的4个字节。


注:不同类型指针占用类型大小相同的指针是不能混用的,因为两者存储在内存中的空间是不同的,int 类型存储的是int类型,float类型存储的是float类型。

#define  _CRT_SECURE_NO_WARNINGS
#include "stdio.h"
#include "stdlib.h"
#include "math.h"
#include <string.h>
#include "add.h"
#include <stdint.h>

/*
****************************
*  DEF    :  指针    
*  参数   :  无参数
*  返回值 :  无返回值
*  时间   :  2024/7/14
*  作者   :  _沧浪之水_
****************************
*/

int main()
{
	int a = 0;
	int* pi = &a;  // pi 解引用访问4个字节,pi + 1 也是跳过4个字节
	float* pf =(float *)& a;// pf 解引用访问4个字节,pf + 1 也是跳过4个字节

	return 0;
}


3.0 野指针,指针,与指针运算

野指针的概念:指的是指针指向的位置是不可知的

int main
{
	// p没有初始化,就意味着没有明确的指向
	// 一个局部变量不初始化,放的是随机值
   int *p;
   // 这样做的方式就是非法的访问内存,这个时候p就是野指针
   *p = 10;
}

#define  _CRT_SECURE_NO_WARNINGS
#include "stdio.h"
#include "stdlib.h"
#include "math.h"
#include <string.h>
#include "add.h"
#include <stdint.h>

/*
****************************
*  DEF    :  指针    
*  参数   :  无参数
*  返回值 :  无返回值
*  时间   :  2024/7/14
*  作者   :  _沧浪之水_
****************************
*/

int main()
{
	int arr[10] = { 0 };
	// 数组名表示数组首元素地址arr[0]
	int* p = arr;
	// 指针的越界访问也会造成野指针
	for (int i = 0; i <= 10; i++) 
	{
		*p = i;
		p++;
	}
	return 0;
}


野指针:涉及到局部变量和全局变量知识

函数执行进入主函数:main

这个时候test() 函数被调用

通过return 返回a的地址地址返回后int a 由于数局部变量出函数之后被销毁

这个时候 int *p 通过地址可以找到a这个空间
但是这个时候a空间已经被销毁,p这个时候无法访问和使用这个空间,这个时候这个p属于是野指针。

int * test()
{
   int a = 10;
   return &a;
}

int main()
{
   int *p = test();
   return 0;
}


4.0 如何避免野指针

NULL 的值相当于是0 ,0 空间是没有办法被指针访问的,避免野指针的方式可以在初始化不知道赋值为什么的时候赋值为一个NULL也就是空指针,同时在使用之前先判断指针是否为空,如果指针为空就不使用,如果指针不为空的时候就对指针变量进行相应的操作,具体的示例如下所示。

避免野指针:

1: 指针初始化,

2:小心数组下标越界,

3:指针指向空间释放及时设置为NULL,

4:避免返回局部变量的地址,

5:使用指针之前先检查指针的有效性。

int * p = NULL;
int mian(void)
{
	if(p != NULL)
	{
		*p3 = 100;
	}
	return 0;

}

指针加减整数运算

#define N_VALUE 5
float values[N_VALUES];
float *vp

for(vp = &values[0]; vp < &values[N_VALUES];)
{
	*vp++ = 0;
}

int main(void)
{
	int arr[10] = { 0 };
	int i = 0;
	int sz = sizeof(arr)/sizeof(arr[0]);
	

	for(i = 0; i < sz; i++)
	{
		// 把数组里面的值全部赋值为 1
		arr[i] = 1;
	}
	// int 类型的指针变量p,数组名等于数组首元素的地址
	int *p = arr;
	for(i = 0; i < sz; i++)
	{
		// *P 解引用:也就是取值的意思
		*p = 1;
		p++;
	
	}
	// 使用指针步长的方式访问数组,进行数组操作
	for(i = 0; i < sz; i++)
	{
		*(p + 1) = 1;
	}
	return 0;

}

5.0 指针加减指针

int main(void)
{
    // 指针减去指针得到的绝对值得到的是指针之间元素的个数
	// 不是所有的指针都能相减,指向同一块空间的指针才能相减
	int arr[10] = { 0 };
	printf("%d\n",&arr[9] - &arr[0]); // 9
}

字符串长度:使用指针减去指针的方式

int my_strlen(char *str)
{*

   // str 刚开始起始地址是a
	int count = 0;
	while(*str != '\0')
	{
		count++;
		str++;
	}
	return count;
}
// 指针 - 指针
int my_strlen(char *str)
{
	char *start = str;
	while(*str != '\0')
	{
		str++;
	}
	return (str - start);

}

int main(void)
{
	int len = my_strlen("abcdef");
	printf("%d\n",len);

}

指针的关系运算

#define N_VALUES 5
float values[N_VALUES]
float *vp;

for(vp = &values[N_VALUES]; vp > &values[0];)
{
	*--p = 0;
}

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


指针遍历访问数组

数组的定义:数组是一组相同元素的集合,指针变量是一个变量,存放的是地址,数组的数组名是首元素的地址 。

int main(void)
{
	int arr[10] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 };
	int *p = arr;
	int len = sizeof(arr)/sizeof(arr[0]);
	int i = 0
	for(i = 0; i < len; i++)
	{
		printf("%d ",*(p + i));
	}
    for(i = 0; i < len; i++)
    {
        // 打印输出的地址结果是相同的
        printf("%p-----------------%p\n",&arr[i],p + i);
    }
	return 0;
}

6.0 二级指针

引入一级指针的概念:

int a  = 10 ; a 是一个int 类型的变量初始值为10

int * pa = &a; pa是一个指针,pa是一个指向int 类型的指针变量,

&a 把 变量a在内存中的地址赋值给指针变量pa ,pa可以通过这个地址找到a并获取a在变量当中的值并修改同时打印输出。

int main()
{
	int a = 10;
	// pa 是一个一级指针变量
	int* pa = &a;
	*pa = 20;
	printf("%d ", a);

	return 0;
}

二级指针变量:程序输出的值是 30 注意理解:int **ppa 中

int main()
{
	int a = 10;
	// pa 是一个一级指针变量
	int* pa = &a;
	int** ppa = &pa;
	**ppa = 30;
	printf("%d ", a);
	return 0;
}

 二级指针存放的是一级指针变量的地址

int main()
{
	int a = 10;
	// pa 是一个一级指针变量
	int* pa = &a;
	int** ppa = &pa;
	**ppa = 30;
	printf("%d ", a);
	return 0;
}

7.0 指针数组

【指针数组:存放指针的数组就是指针数组】

int main()
{
	int a = 10;
	int b = 20;
	int c = 30;

	int arr[10];

	int* pa = &a;
	int* pb = &b;
	int* pc = &c;
	// parr 是存放指针的数组,称之为指针数组
	int* parr[10] = { &a, &b, &c };

	int i = 0;
	int len = sizeof(parr) / sizeof(parr[0]);
	for (i = 0; i < len; i++) 
	{
		printf("%d ", *(parr[i]));
	}
	return 0;
}

【补充:二维数组创建与遍历】

/*
****************************
*  DEF    :  二级指针    
*  参数   :  无参数
*  返回值 :  无返回值
*  时间   :  2024/7/15
*  作者   :  _沧浪之水_
****************************
*/

int main()
{
	int arr[3][4] = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10};
	int i = 0;
	int j = 0;
	for (i = 0; i < 3; i++) 
	{
		for (j = 0; j < 4; j++) 
		{
			printf("%d  ", arr[i][j]);
		}
		printf("\n");
	}
	return 0;
}

指针模拟二维数组

int main()
{
	int arrOne  [4] = { 1, 2, 3, 4 };
	int arrTwo  [4] = { 2, 3, 4, 5 };
	int arrThree[4] = { 6, 7, 8, 9 };

	int* parr[3] = { arrOne,  arrTwo, arrThree };

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

......

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

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

相关文章

本地部署,Flash Diffusion: 加速条件扩散模型实现快速图像生成

目录 引言 技术背景 Flash Diffusion 的架构与原理 Flash Diffusion 的主要特点 本地部署 运行结果 实验结果与分析 应用实例 结论 GitHub - gojasper/flash-diffusion: Official implementation of ⚡ Flash Diffusion ⚡: Accelerating Any Conditional Diffusion M…

uniapp:国家、省市区,4级联动

使用uview的Select 列选择器 选择器完成国家&#xff0c;省市区&#xff0c;4级联动 要求后台数据格式&#xff1a; list: [{label: 中国,value: 1,children: [{label: 河南省,value: 2,children: [{label: 郑州市,value: 3,children: [{label: 中原区,value: 4},{label: 郑东…

系统架构师考点--系统安全

大家好。今天我来总结一下系统安全相关的考点&#xff0c;这类考点每年都会考到&#xff0c;一般是在上午场客观题&#xff0c;占2-4分。 一、信息安全基础知识 信息安全包括5个基本要素&#xff1a;机密性、完整性、可用性、可控性与可审查性 (1)机密性&#xff1a;确保信息…

嵌入式智能手表项目实现分享

简介 这是一个基于STM32F411CUE6和FreeRTOS和LVGL的低成本的超多功能的STM32智能手表~ 推荐 如果觉得这个手表的硬件难做,又想学习相关的东西,可以试下这个新出的开发板,功能和例程demo更多!FriPi炸鸡派STM32F411开发板: 【STM32开发板】 FryPi炸鸡派 - 嘉立创EDA开源硬件平…

IMS架构中的注册与会话流程:RTPEngine集成及消息路由详解

目录 S-CSCF 调用 RTPengine 整体路由 注意 IMS 注册流程 和 IMS 会话流程 的区别 IMS注册流程 IMS会话流程(如INVITE请求) 这种设计的原因 P-CSCF 调用 RTPengine S-CSCF 调用 RTPengine 整体路由 UA a生成SDP offer&#xff0c;发送SIP INVITE请求(包含SDP offer)&…

MySql 数据库 - 下载安装

MySQL数据库 简单介绍 数据库 数据存储的仓库数据库管理系统 操作和管理数据库的大型软件SQL 操作关系型数据库的变成语言&#xff0c;是一套标准 版本 MySQL官方提供了两种不同的版本&#xff1a; 社区版 免费&#xff0c;MySQL不提供任何的技术支持商业版 收费&#xff0c…

数据结构(单链表(1))

前言 线性表中有着许多的结构&#xff0c;如顺序表和链表。而单链表则是链表的最基础的一种形式&#xff0c;下面就让我们对其做一个了解。 概念 概念&#xff1a;链表是⼀种物理存储结构上⾮连续、⾮顺序的存储结构&#xff0c;数据元素的逻辑顺序是通过链表中的指针链接次…

【python】Pandas中`ValueError: cannot reindex from a duplicate axis`错误分析

✨✨ 欢迎大家来到景天科技苑✨✨ &#x1f388;&#x1f388; 养成好习惯&#xff0c;先赞后看哦~&#x1f388;&#x1f388; &#x1f3c6; 作者简介&#xff1a;景天科技苑 &#x1f3c6;《头衔》&#xff1a;大厂架构师&#xff0c;华为云开发者社区专家博主&#xff0c;…

构建GitLab代码私有仓库

构建代码私有仓库 公司代码仓库一般都放在git上&#xff0c;但为了安全一般都不会放在开放的git上&#xff0c;都会搭建自己的仓库&#xff0c;今天就记录一下git搭建的过程。以下安装过程以centos7为例&#xff1a; 步骤一&#xff1a;安装并配置依赖项&#xff0c;同时打开ht…

解决gitlab报502的问题

external_url http://10.7.24.6:10002 puma[port] 8091 sudo gitlab-ctl reconfigure sudo gitlab-ctl restart 设置管理员密码&#xff1a; 1. 切换目录&#xff1a;cd 安装目录gitlab的bin目录下 2. 以root执行 &#xff1a;gitlab-rails console命令&#xff0c;等待…

HTTP背后的故事:理解现代网络如何工作的关键(一)

一.HTTP是什么 概念 &#xff1a; 1.HTTP ( 全称为 " 超文本传输协议 ") 是一种应用非常广泛的 应用层协议。 2.HTTP 诞生与1991年. 目前已经发展为最主流使用的一种应用层协议. 3.HTTP 往往是基于传输层的 TCP 协议实现的 . (HTTP1.0, HTTP1.1, HTTP2.0 均为 T…

Linux离线安装Mysql5.7

Linux之Mysql安装配置 第一种&#xff1a;Linux离线安装Mysql&#xff08;提前手动下载好tar.gz包&#xff09; 第二种&#xff1a;通过yum安装配置Mysql&#xff08;服务器有网络&#xff09; 之前在阿里云上采用yum安装过一次&#xff08;请看这里&#xff09;&#xff0c;…

文心一言 VS 讯飞星火 VS chatgpt (303)-- 算法导论22.2 1题

一、请计算出在有向图22-2(a)上运行广度优先搜索算法后的d值和π值。这里假定结点3为算法所用的源结点。如果要写代码&#xff0c;请用go语言。 文心一言&#xff1a; 在Go语言中实现广度优先搜索&#xff08;BFS&#xff09;以计算有向图上的距离&#xff08;d值&#xff09…

【Java--数据结构】队列与栈的相互成就

欢迎关注个人主页&#xff1a;逸狼 创造不易&#xff0c;可以点点赞吗~ 如有错误&#xff0c;欢迎指出~ 目录 用队列实现栈 用栈实现队列 用队列实现栈 oj链接 一个队列是无法实现栈的 入栈push&#xff1a;把数据放到不为空的队列当中。 注意&#xff1a;第一次入栈时&…

【K8s】专题七(2):Kubernetes 服务发现之 Ingress

以下内容均来自个人笔记并重新梳理&#xff0c;如有错误欢迎指正&#xff01;如果对您有帮助&#xff0c;烦请点赞、关注、转发&#xff01;欢迎扫码关注个人公众号&#xff01; 目录 一、基本介绍 二、工作原理 三、资源清单&#xff08;示例&#xff09; 1、Ingress Cont…

为什么要使用加密软件?

一、保护数据安全&#xff1a;加密软件通过复杂的加密算法对敏感数据进行加密处理&#xff0c;使得未经授权的人员即使获取了加密数据&#xff0c;也无法轻易解密和获取其中的内容。这极大地提高了数据在存储、传输和使用过程中的安全性。 二、遵守法律法规&#xff1a;在许多国…

MMLab-dataset_analysis

数据分析工具 这里写目录标题 数据分析工具dataset_analysis.py数据可视化分析 benchmark.pybrowse_coco_json.pybrowse_dataset.pyOptimize_anchors mmyolo、mmsegmentation等提供了数据集分析工具 dataset_analysis.py 数据采用coco格式数据 根据配置文件分析全部数据类型或…

方便好用的C#.Net万能工具库Masuit.Tools

文章目录 简介开发环境安装使用特色功能示例代码1. 检验字符串是否是Email、手机号、URL、IP地址、身份证号等2.硬件监测(需要管理员权限&#xff0c;仅支持Windows&#xff0c;部分函数仅支持物理机模式)3.html的防XSS处理&#xff1a;4.整理Windows系统的内存&#xff1a;5.任…

STM32智能停车场管理系统教程

目录 引言环境准备智能停车场管理系统基础代码实现&#xff1a;实现智能停车场管理系统 4.1 数据采集模块 4.2 数据处理与控制模块 4.3 通信与网络系统实现 4.4 用户界面与数据可视化应用场景&#xff1a;停车场管理与优化问题解决方案与优化收尾与总结 1. 引言 智能停车场管…

【LeetCode 链表合集】

文章目录 1. LeetCode 206 反转链表2. NC40 链表相加 1. LeetCode 206 反转链表 题目链接&#x1f517; 解题思路&#xff1a; &#x1f50d; &#x1f427;创建一个新的节点&#xff0c;使用链表头插的方法&#xff1b; 2. NC40 链表相加 题目链接&#x1f517; 解题思路…