指针——C语言初阶

news2025/1/11 7:06:56

一.指针基本概念:

  1. 指针是内存中一个最小单元的编号,也就是地址
  2. 平时口语中说的指针,通常指的是指针变量,是用来存放地址的变量
    #include<stdio.h>
    int main()
    {
    	int a = 0;
        //a是整型变量,占用四个字节的内存空间,在内存中开辟一块空间
    	int* pa = &a;
    	printf("%p", pa);
    	//pa是一个指针变量,用来存放地址,这里是将a的四个字节的第一个字节的地址存放在ap变量中
    	return 0;
    }

  3. 指针变量:我们可以通过&(取地址操作符)取出变量的内存真实地址,把地址可以存放到一个变量中这个变量就是指针变量。(存放在指针中的值都被当成地址处理)
  4. 指针变量中存放的是地址,通过这个地址,就可以找到一个内存单元
  5. 指针的大小在32位平台是四个字节,在64位平台是八个字节
  6. x86  - 32位

    x64  - 64位


二.指针和指针类型:

  1. 我们都知道普通变量都有不同的类型,由整型,字符型,浮点型等等,而指针变量也有不同的类型
    int a = 5;
    
    假设有以上a变量,那么我们可以将a的地址储存进以下指针变量中
    
    char* pc = &a;
    
    short* ps = &a;
    
    int* pi = &a;
    
    long* pl = &a;
    
    float* pf = &a;
    
    double* pd = &a;
    
  2. 我们需要注意的是:例如:int*p——指针类型是int*,指针所指向的类型是int。(不要记混)
  3. 既然一个整型类型的数据可以被别的不同类型数据的指针储存,那么指针类型的意义又是什么呢?

(1)指针+-整数:

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

(2)指针的解引用:
#include<stdio.h>
int main()
{
	int n = 0x11223344;
	char* pc = (char*)&n;
	int* pi = &n;
	*pc = 0;//重点在调试的过程中观察内存的变化
	*pi = 0;//重点在调试的过程中观察内存的变化
	return 0;
}

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

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


三.野指针:

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

(1)野指针成因:
  1. 指针未初始化:
    #include<stdio.h>
    int main()
    {
    	int* p;
    	//p没有初始化,就意味着没有明确的指向
    	//一个局部变量不初始化的话,放的是随机值
    	*p = 10;//非法访问内存了
    	return 0;
    }

  2. 指针越界访问:
    #include<stdio.h>
    int main()
    {
    	int arr[10] = { 0 };
    	int* p = arr;
    	int i = 0;
    	for (i = 0; i <= 11; i++)
    	{
    		//当指针范围超出数组arr的范围时,p就是野指针
    		*(p++) = i;
    	}
    	return 0;
    }

  3. 指针指向的空间释放:
    #include<stdio.h>
    int* test()
    {
        int a = 10;
        //a为局部变量,函数开始时创建,函数结束时销毁
        return &a;
    }
    int main()
    {
        int* p = test();
        *p = 20;
        //此时p指向的空间已销毁(被释放),不属于当前程序,此时指针p就为野指针
        return 0;
    }
    

(2)如何规避野指针:
  1. 指针初始化:
  2. 注意指针是否越界
  3. 指针指向被释放空间时置为NULL(空指针)
  4. 指针使用之前应检查其有效性

这里展示几个代码:

比较以下代码,并注意注释的内容:

函数栈帧与销毁:


四.指针运算:

(1)指针+-整数:

总结:

  • 从0位到5位,地址是由低到高的
  • *p++=0;相当于:*p=0   p++  
  • 指针变量的自增自减运算,指针加一或减一运算,表示指针向前或向后移动一个单位(不同类型的指针,单元长度不同 )。这个在数组中非常常用。
    #include<stdio.h>
    int main()
    {
    	int arr[10] = { 0 };
    	int i = 0;
    	int n = sizeof(arr) / sizeof(arr[0]);//计算出数组中元素的个数
    	/*for (i = 0; i < n; i++)
    	{
    		arr[i] = 1;
    	}*/
    	int* p = &arr[0];
    	for (i = 0; i < n; i++)
    	{
    		*p++ = 1;//*(p+i)=1
    	}
    	return 0;
    }

(2)指针-指针:

观察下图:

可以很直观的得出:数组中两个指针相减得到的是指针和指针之间元素的个数

注意:

  • 不是所有指针都能相减
  • 指向同一块空间的两个指针才能相减!

例题:编写函数(不允许创建临时变量),求字符串的长度(三种方法)

  • 循环
  • 递归
  • 指针-指针
//循环
#include<stdio.h>
int my_strlen(char* n)
{
	int count = 0;
	while (*n != '\0')
	{
		count++;
		n++;
	}
	return count;
}
int main()
{
	int len = my_strlen("lover");
	printf("%d", len);
	return 0;
}
//递归
#include<stdio.h>从
int my_strlen(char* n)
{
	if (*n != '\0')
	{
		return 1 + my_strlen(n + 1);
	}
	else
	{
		return 0;
	}
}
int main()
{
	int len = my_strlen("lover");
	printf("%d", len);
	return 0;
}
//指针-指针
#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
int my_strlen(char* n)
{
	char* np = n;
	while (*n != '\0')
	{
		n++;
	}
	return n - np;
}
int main()
{
	char arr[] = "study";
	int len = my_strlen(arr);
	printf("%d", len);
	return 0;
}

(3)指针的关系运算:

#include<stdio.h>
#define A 5
int main()
{
	int arr[10] = { 0 };
	int* p = &arr[A];
	for (p = &arr[A]; p > &arr[0];)
	{
		*--p = 0;
	}
	return 0;
}

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


五.指针和数组:

  1. 数组名表示的是数组首元素地址(两种情况除外,数组章节讲了——sizeof,&)

(不必多说,数组那节都已经讲了)


六.二级指针:

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

观察下面代码:

  1. pa是一个指针变量,一级指针
  2. ppa是一个二级指针变量
  3. int*是说明ppa是指针,ppa指向的对象是int*类型


七.指针数组:

指针数组是数组,是存放指针的数组(数组我们已经了解了整型数组,字符数组)

观察下列代码:

#include<stdio.h>
int main()
{
	int a = 10;
	int b = 20;
	int c = 30;
	int arr[10];
	int* ap = &a;
	int* bp = &b;
	int* cp = &c;
	//parr是存放指针的数组,就是指针数组
	int* parr[10] = { &a,&b,&c };
	int i = 0;
	for (i = 0; i < 3; i++)
	{
		printf("%d\n", *(parr[i]));
	}
	return 0;
}

可以用其打印二维数组:

#include<stdio.h>
int main()
{
	int arr1[4] = { 1,2,3,4 };
	int arr2[4] = { 2,3,4,5 };
	int arr3[4] = { 3,4,5,6 };
	int* parr[3] = { &arr1,&arr2,&arr3 };
	int i = 0;
	for (i = 0; i < 3; i++)
	{
		int j = 0;
		for (j = 0; j < 4; j++)
		{
			printf("%d", parr[i][j]);//相当于:arri[j]
			//parr[1]相当于arr1,也可以改为 *( *(parr+i)+j)
			//arr[i] <==> *(arr+i)
		printf("\n");
	}
	return 0;
}

知识点:arr[i] <==> *(arr+i)

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

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

相关文章

大型语言模型中的幻觉研究综述:原理、分类、挑战和未决问题11.15+11.16+11.17

大型语言模型中的幻觉研究综述&#xff1a;原理、分类、挑战和未决问题11.15 摘要1 引言2 定义2.1 LLM2.3 大语言模型中的幻觉 3 幻觉的原因3.1 数据的幻觉3.1.1 有缺陷的数据源3.1.2 较差的数据利用率3.1.3 摘要 3.2 来自训练的幻觉3.2.1训练前的幻觉3.2.2来自对齐的幻觉3.2.3…

同时显示上下两层凸包特征的可视化程序

数据类型 std::vector<pcl::PointCloud<pcl::PointXYZ>::Ptr> hulls_k_upper std::vector<pcl::PointCloud<pcl::PointXYZ>::Ptr> hulls_k_lower std::vector<pcl::PointCloud<pcl::PointXYZ>::Ptr> hulls_underk_upper std::vector<…

群晖7.2安装Jellyfin+alist+CloudDriver搭建无盘影院中心

群晖7.2安装JellyfinalistCloudDriver搭建无盘影音中心。 实现思路如下&#xff1a; Jellyfin&#xff1a;提供个人影院功能。 alist&#xff08;xiaoya&#xff09;&#xff1a;给影院提供海量影音资源。 CloudDriver2&#xff1a;alist的资源为网络资源&#xff0c;通过C…

搭建yum源并定时同步

一 、安装yum源 1-准备yum目录 cd /data/www/html createrepo -v ./目录 2-安装服务 yum -y install httpd 3-配置服务 /etc/httpd/conf/httpd.conf 4.配置/etc/yum.repo.d/local.rpeo 二、定时更新yum源 #1. 同步整个源到指定目录 [rootV10SP1-1 pac]# reposync -p /root/…

C语言--写一个函数返回bool值,来判断给定的字符串A和B(假设都是小写字母),是否是B中的字符都存在于A中,如果是返回true,否则返回false

一.题目描述 写一个函数返回bool值&#xff0c;来判断给定的字符串A和B&#xff08;假设都是小写字母&#xff09;&#xff0c;是否是B中的字符都存在于A中&#xff0c;如果是返回true&#xff0c;否则返回false。例如&#xff1a; 字符串A&#xff1a;abcde 字符串B&#xff…

长短期记忆(LSTM)与RNN的比较:突破性的序列训练技术

长短期记忆&#xff08;Long short-term memory, LSTM&#xff09;是一种特殊的RNN&#xff0c;主要是为了解决长序列训练过程中的梯度消失和梯度爆炸问题。简单来说&#xff0c;就是相比普通的RNN&#xff0c;LSTM能够在更长的序列中有更好的表现。 Why LSTM提出的动机是为了解…

windows使用lcx端口转发登陆远程主机

1.编译lcx源码: GitHub - UndefinedIdentifier/LCX: 自修改免杀lcx端口转发工具 2.在win7上安装vs2010并编译生成lcx.exe 3.在要被控制主机上运行: lcx -slave 192.168.31.248 51 192.168.31.211 3389 192.168.31.248为远程主控制主机,51为远程主机端口 192.168.31.211为被…

ZYNQ7000---FLASH读写

提示&#xff1a;写完文章后&#xff0c;目录可以自动生成&#xff0c;如何生成可参考右边的帮助文档 文章目录 前言一、Flash是什么&#xff1f;二、Flash的分类1、内部结构&#xff08;接口&#xff09;区分&#xff1a;2、外部接口区分&#xff1a;SPIQPSI Flash: QSPI 控制…

Leetcode刷题详解——猜数字大小 II

1. 题目链接&#xff1a;375. 猜数字大小 II 2. 题目描述&#xff1a; 我们正在玩一个猜数游戏&#xff0c;游戏规则如下&#xff1a; 我从 1 到 n 之间选择一个数字。你来猜我选了哪个数字。如果你猜到正确的数字&#xff0c;就会 赢得游戏 。如果你猜错了&#xff0c;那么我…

分发糖果(贪心算法)

题目描述 n 个孩子站成一排。给你一个整数数组 ratings 表示每个孩子的评分。 你需要按照以下要求&#xff0c;给这些孩子分发糖果&#xff1a; 每个孩子至少分配到 1 个糖果。相邻两个孩子评分更高的孩子会获得更多的糖果。 请你给每个孩子分发糖果&#xff0c;计算并返回…

操作系统:输入输出管理(二)磁盘调度算法

一战成硕 5.3 磁盘固态硬盘5.3.1 磁盘5.3.2 磁盘的管理5.3.3 磁盘调度算法 5.3 磁盘固态硬盘 5.3.1 磁盘 磁盘是表面涂有磁性物质的物理盘片&#xff0c;通过一个称为磁头的导体线圈从磁盘存取数据。在读写操作中&#xff0c;磁头固定&#xff0c;磁盘在下面高速旋转。磁盘盘…

Linux安装DMETL5与卸载

Linux安装DMETL5与卸载 环境介绍1 DM8数据库配置1.1 DM8数据库安装1.2 初始化达梦数据库1.3 创建DMETL使用的数据库用户 2 配置DMETL52.1 解压DMETL5安装包2.2 安装调度器2.3 安装执行器2.4 安装管理器2.5 启动dmetl5 调度器2.6 启动dmetl5 执行器2.7 启动dmetl5 管理器2.8 查看…

LangGPT作者教你编写高质量提示词

CoT和ToT能够提升表现&#xff0c;但是会使得模型的使用变复杂。在对话的场景下容易消耗人的耐心&#xff1b;实际应用的场景下&#xff0c;比较消耗人的token。 还有一点需要说明的是&#xff0c;我们在写自己的prompt的时候&#xff0c;不应该盲目地追求和堆砌提示词技巧&am…

Unity 预制体放在场景中可见,通过代码复制出来不可见的处理

首先我制作了一个预制体&#xff0c;在场景中是可见的&#xff0c;如下图 无论是Scene视图&#xff0c;还是Game视图都正常。 我把预制体放到Resources里面&#xff0c;然后我通过如下代码复制到同个父物体下。 GameObject obj1 Instantiate(Resources.Load("Butcon&quo…

Django+vue前后端分离实战--vue后台管理系统--vue环境安装项目创建

Djangovue前后端分离实战--vue后台管理系统 安装nodejsvue clivue-cli创建项目 安装nodejsvue cli 1、下载nodejs并安装 https://nodejs.org/dist/v20.9.0/node-v20.9.0-x64.msi 2、修改npm 默认仓库地址&#xff0c;要修改成taobao的镜像npm 仓库地址 cmd下命令&#xff1a…

sql注入 [极客大挑战 2019]LoveSQL 1

打开题目 几次尝试&#xff0c;发现输1 1"&#xff0c;页面都会回显NO,Wrong username password&#xff01;&#xff01;&#xff01; 只有输入1&#xff0c;页面报错&#xff0c;说明是单引号的字符型注入 那我们万能密码试试能不能登录 1 or 11 # 成功登录 得到账号…

【Redis】springboot整合redis(模拟短信注册)

要保证redis的服务器处于打开状态 上一篇&#xff1a; 基于session的模拟短信注册 https://blog.csdn.net/m0_67930426/article/details/134420531 整个流程是&#xff0c;前端点击获取验证码这个按钮&#xff0c;后端拿到这个请求&#xff0c;通过RandomUtil 工具类的方法生…

微服务实战系列之Token

前言 什么是“Token”&#xff1f; 它是服务端生成的一串字符串&#xff0c;以作客户端进行请求的一个令牌&#xff0c;当第一次登录后&#xff0c;服务器生成一个Token便返回给客户端&#xff1b;以后客户端只携带此Token请求数据即可。 简言之&#xff0c;Token其实就是用户身…

VBA_MF系列技术资料1-222

MF系列VBA技术资料 为了让广大学员在VBA编程中有切实可行的思路及有效的提高自己的编程技巧&#xff0c;我参考大量的资料&#xff0c;并结合自己的经验总结了这份MF系列VBA技术综合资料&#xff0c;而且开放源码&#xff08;MF04除外&#xff09;&#xff0c;其中MF01-04属于定…

Rxswift(1)

基础用法 数据绑定核心Observerable 可监听序列 数据绑定 平常的写法 let image: UIImage UIImage(named: ...) imageView.image image绑定的写法 //可监听序列 let image: Observable<UIImage> ... //imageView.rx.image 观察者 image.bind(to: imageView.rx.image…