C语言——指针基础

news2024/12/27 3:10:30

1 指针基础

怎么获得变量地址

在这里插入图片描述

1   如何产生一个指针变量
	——>类型* 标识符;
	int* p1;
	char* p2;
	double* p3;
	//不同类型的基本指针占用内存是一样的都是4个字节(32位)/8个字节(64位),都是存的地址


2 数组名是数组首地址但不是普通指针
  ——>数组名绑定的一段内存可以影视转化为指针
  int array[4] = { 1,2,3,4};
	printf("array:%zd\n", sizeof(array));//打印16,整个数组的大小
	printf("array:%p\tarray[0]:%p", array, &array[0]);//值一样,内容不一样


3  int*p1;未初始化是野指针
   p1=NULL;变成空指针。
   NULL-->(void*)00强制转化地址
   一般定义指针 int*p=NULL;


4 指针取值运算
 int num=666;
 int*P=#
 //*指针变量 ,指针变量[0];
 printf("%d\t%d\t%d\n", num, *pnum, pnum[0]);//都打印666
 *pume=888printf("%d\t%d\t%d\n", num, *pnum, pnum[0]);//都打印888
 //操作指针变量*pume就相当于操作num,任意修改一个其他都会跟着变

5 指针偏移——>移动数据位
 //p+n或者p-n是移动数据位
 //int* p
 要明白指针类型
 //指针的类型:int*  -->去掉变量名
 //指针的所指向类型:int-->操作的数据的类型-->去掉变量名和*号(基类型)
 //知道操作的数据类型就知道偏移多少
 printf("p1=%p\n", p1);     int p1=0000000000000000
 printf("p2=%p\n", p2);		char p2=0000000000000000
 printf("p3=%p\n", p3);  	double p3=0000000000000000
 //+1,偏移一个数据位   
 printf("p1=%p\n", p1+1);  	int p1=0000000000000004
 printf("p2=%p\n", p2+1);   char p2=0000000000000001
 printf("p3=%p\n", p3+1);   double p3=0000000000000008
   
 printf("array=%p\n", array);   array=000000A8A24FF4C8
 printf("array=%p\n", array+1); array=000000A8A24FF4CC //差4
    
 int(*p)[3] = NULL;    
 printf("p=%p\n", p );	  //操作的是int[3]
 printf("p=%p\n", p + 1);  //int[3]——>偏移一个数组12个字节

2 const与指针变量

const后面不能被修改,把变量变成了常属性。 
    
1.以下两种没区别
const int cnum1 = 0;
int const cnum2 = 0;

2.*前面,指针指向内容不可以修改——>修饰1
//以下两种没区别
//const描述的是指针所指向的内容
const int* p1 = &cnum1;
int const* p2 = &cnum1;
int data = 0;
*p1=666;(不行)
p1 = &data;
p1 = p2;(可以)

3*后面,指针不可以修改——>修饰2
 //让指针变量指向的地址固定
int* const p3 = &data;
//const修饰的是p3 不可修改
p3 = p2; (不行)
p2 = p3;(可以)
    
4const int* const p4 = &data;
//都不能被修改

在这里插入图片描述

3 二级指针与多级指针

因为指针变量也有地址,也可以用指针来存放
类似与套娃
int num = 0;
int* p1 = #
int** p2 = &p1;
int*** p3 = &p2;

num = 999;
printf("%d\n", ***p3);
printf("%d\n", p3[0][0][0]);//这两个也一样都打印999

4 指针操作一维数组

指针指向数组首地址,直接当数组名去用

1
    int array[4] = { 1,2,3,4 };
	int* p = array;
	//p = &array[0];
	for (int i = 0; i < 4; i++)
{
	printf("%d\t", p[i]);		//推荐用法
	//printf("%d\t", *(p + i));
	//printf("%d\t", (p + i)[0]);
}

	//下面用法不推荐,但是要能看懂
	//改变指针指向,指针偏移到数组之后,任意越界用起来危险
	while (p != array + 4)
{
	printf("%d\t", p++[0]);
}
	printf("\n");

2 负下标,不用首地址做初始化
    
int data[10] = { 1,2,3,4,5,6,7,8,9,10 };
int* pp = &data[5];
printf("%d\n", pp[0]);
for (int i = -4; i < 0; i++) 
{
	printf("%d\t", pp[i]);
}
printf("\n");



3  函数传参,传输组名等效于传一级指针(数字类必须还要传长度)
   在 C 语言中,数组作为函数参数时,实际上是传递数组的首地址,而不是整个数组。
   因此,函数内部无法直接获取数组的长度。这就是为什么我们需要额外传递数组的长度(元素数量)的原因
    
    void print_array(int array[], int arrayNum) 
{
	for (int i = 0; i < arrayNum; i++) 
	{
		printf("%d\t", array[i]);
	}
	printf("\n");
}
void print_array_2(int *array, int arrayNum)
{
	for (int i = 0; i < arrayNum; i++)
	{
		printf("%d\t", array[i]);
	}
	printf("\n");
}


4 传字符串一定要写const,C语言里可能没有影响,c++有影响(养成好习惯)
int my_strlen(const char* str) 
{
	int count = 0;
	while (str[count] != '\0')
		count++;
	return count;
}

5 指针操控二维数组

1  一级指针操作二维数组——>列转换为序号
    void test_one() 
{
	int array[3][4] = { 1,2,3,4,5,6,7,8,9,10,11,12 };
	int* p = &array[0][0];
	for (int i = 0; i < 3; i++) 
	{
		for (int j = 0; j < 4; j++) 
		{
			//行列转换为序号
			printf("%d\t", p[i * 4 + j]);
		}
		printf("\n");
	}
    
2  数组指针操作
    
    void test_two() 
{
	int array[3][4] = { 1,2,3,4,5,6,7,8,9,10,12 };
	//二维数组名偏移的一行
	printf("array:%p\n", array);
	printf("array+1:%p\n", array+1);  //16
	//二维数组名+一个下标 转换为一个一级指针
	printf("array[0]:%p\n", array[0]);
	printf("a rray[0]+1:%p\n", array[0]+1); //4;

    
    
	2.1//推荐用法!!! 
	//数组指针操作二维数组(直接当数组名)
	int(*p)[4] = array;
	for (int i = 0; i < 3; i++) 
	{
		for (int j = 0; j < 4; j++) 
		{
			printf("%d\t", p[i][j]);
		}
		printf("\n");
	}
    
    
    
    以下是多种写法,用A换元思想(书本上出现要认识)
	2.2 for (int i = 0; i < 3; i++)
	{
		for (int j = 0; j < 4; j++)
		{
			printf("%d\t", *(*(p+i)+j));
			//p[i]==>A  A[j]==>*(A+j)
			//p[i]==>*(p+i)==>A
		}
		printf("\n");
	}
    
	2.3		printf("%d\t", *(p[i] + j));
			//p[i]==>A  A[j]==>*(A+j)
			//p[i]==>A
		
	2.4		printf("%d\t", ((p + i)[0] + j)[0]);
			//p[i]==>A  A[j]==>*(A+j)==>(A+j)[0]
			//p[i]==>(p+i)[0]==>A
	
	2.5		printf("%d\t", (p[i] + j)[0]);
			//p[i]==>A  A[j]==>*(A+j)==>(A+j)[0]
			//p[i]==>(p+i)[0]==>A

    
    
    
 3  函数传参
     void print_array(int(*p)[4], int row, int cols)
{
	for (int i = 0; i < row; i++) 
	{
		for (int j = 0; j < cols; j++) 
		{
			printf("%d\t", p[i][j]);
		}
		printf("\n");
	}
}
void test_three() 
{
	int array[3][4] = { 1,2,3,4,5,65,7,8,9,0,19,12 };
	print_array(array, 3, 4);
}

6 万能指针

#include <stdio.h>
#include <stdlib.h>
int main() 
{
    
//万能指针
void* p = NULL;
int num = 999;
p = &num;

//万能指针不能*p直接访问
//要做目标数据类型的强制类型转换
printf("%d\n", *(int *)p);
double dNum = 8.98;
p = &dNum;
printf("%.2lf\n", *(double*)p);
    
return 0;

7 指针函数

#include <stdio.h>
#include <stdlib.h>.	传指针问题
        
1	//值传递
	void modify_one(int a)  //int a=实参
	{
		a = 100;
	}
	//没有返回值,打印出来还是0


	//址传递(函数不需要返回值就可以修改值)
2	//修改实参的值 ,传入实参的地址,修改是*地址
	void modify_two(int* p) //int* p=实参 
	{
		*p = 100;
	}

3	//(为什么传二级指针)修改指针指向num指向g_num,用二级指针接收指针的地址
    int g_num = 999;
	void modify_point(int** p)   //int** p=实参
	{
		*p = &g_num;
	}
//——————————————————————————————————————————————
int main(){
  1 int num = 0;
	modify_one(num);
	printf("%d\n", num);
//——————————————————————————————————————————————    
  2 modify_two(&num);
	printf("%d\n", num);
//——————————————————————————————————————————————   
  3	int* p = &num;
	modify_point(&p);//传入的指针变量
	printf("%d\n", p[0]);
}

.	返回指针问题
        
1	//C语言不允许返回局部变量的地址(不安全的)
    //内存会回收,变量地址给其他不知道的东西了
	//warning C4172: 返回局部变量或临时变量的地址: num
	int* get_num() 
	{
		int num = 99999;
		return &num;(不行)
	}

2 	//需要学会区分什么叫做局部变量的地址
	int* get_num_one(int* p) 
	{
		return p;(可以)——>因为在主函数里调用时,变量一直到结束时都是有效的
	}

3	//可以返回堆区内存的地址(下章说)

4	//返回一个数组的函数(返回数组首地址就可以了)
	int array[3] = { 1,2,3 };
	int* get_array() 
	{
		return array;
	}

int main() 
{
  1 int* pp = get_num();
	printf("%d\n", *pp);
	printf("%d\n", *pp);
//——————————————————————————————————————————————    
  2 get_num_one(p);//函数返回指针后还可以的继续操作
	//p[0];
	get_num_one(p)[0];
	//*p=199;
	*get_num_one(p) = 199;
	printf("%d\n", g_num);
//——————————————————————————————————————————————
  4 int* parray = get_array();
	for (int i = 0; i < 3; i++) 
	{
		printf("%d\n", parray[i]);
	}
	printf("\n");
	return 0;
}

在这里插入图片描述

!!!这里先看一下指针函数和函数指针的区别,下篇会将到函数指针,容易弄混!!!

在这里插入图片描述

在这里插入图片描述

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

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

相关文章

Leetcode day1.两数相加(2) 2.整数反转(7)

注意点&#xff1a;1.链表会出现其中一个已经为空&#xff0c;另一个缺还是有数据 2.相加时会出现进位操作 解法一、 利用队列的性质&#xff08;基础不好 第一时间想到的&#xff09; 很像队列的性质&#xff0c;先进先出&#xff0c;逐步计算。但是最后要换成链表样式。 …

在Ubuntu-22.04 [WSL2]中配置Docker

文章目录 0. 进入Ubuntu-22.041. 更新系统软件包2. 安装Docker相关依赖包3. 添加Docker官方GPG密钥4. 添加Docker软件源5. 安装Docker Engine5.1 更新软件包列表5.2 安装Docker相关软件包 6. 验证Docker安装是否成功6.1 查看Docker版本信息6.2 启动Docker6.3 配置镜像加速器6.4…

51单片机应用开发(进阶)---串口接收字符命令

实现目标 1、巩固UART知识&#xff1b; 2、掌握串口接收字符数据&#xff1b; 3、具体实现目标&#xff1a;&#xff08;1&#xff09;上位机串口助手发送多字符命令&#xff0c;单片机接收命令作相应的处理&#xff08;如&#xff1a;openled1 即打开LED1;closeled1 即关…

【查询基础】.NET开源 ORM 框架 SqlSugar 系列

&#x1f4a5; .NET开源 ORM 框架 SqlSugar 系列 &#x1f389;&#x1f389;&#x1f389; 【开篇】.NET开源 ORM 框架 SqlSugar 系列【入门必看】.NET开源 ORM 框架 SqlSugar 系列【实体配置】.NET开源 ORM 框架 SqlSugar 系列【Db First】.NET开源 ORM 框架 SqlSugar 系列…

基于Matlab BP神经网络的电力负荷预测模型研究与实现

随着电力系统的复杂性和规模的不断增长&#xff0c;准确的电力负荷预测对于电网的稳定性和运行效率至关重要。传统的负荷预测方法依赖于历史数据和简单的统计模型&#xff0c;但这些方法在处理非线性和动态变化的负荷数据时&#xff0c;表现出较大的局限性。近年来&#xff0c;…

LeetCode - #150 逆波兰表达式求值

文章目录 前言1. 描述2. 示例3. 答案关于我们 前言 我们社区陆续会将顾毅&#xff08;Netflix 增长黑客&#xff0c;《iOS 面试之道》作者&#xff0c;ACE 职业健身教练。&#xff09;的 Swift 算法题题解整理为文字版以方便大家学习与阅读。 LeetCode 算法到目前我们已经更新…

mysql基础学习1

useradd -r -g mysql -s /bin/false mysql (-r)系统用户 不能登录 A temporary password is generated for rootlocalhost: d>#jT7rfoaz) 看是否启动 看进程 端口 直接连接 看日志 varchar (20) char(20)更耗空间 create table student_info(id int,name varchar(20),s…

PPT怎样做的更加精美

目录 PPT怎样做的更加精美 3D的GIF图片 3维空间图​编辑 结果有明显的对比 阅读高质量文献,采用他们的图 PPT怎样做的更加精美 3D的GIF图片 3维空间图 结果有明显的对比

Marvell第四季度营收预计超预期,定制芯片需求激增

芯片制造商Marvell Technology&#xff08;美满电子科技&#xff09;&#xff08;MRVL&#xff09;在周二发布了强劲的业绩预告&#xff0c;预计第四季度的营收将超过市场预期&#xff0c;得益于企业对其定制人工智能芯片的需求激增。随着人工智能技术的快速发展&#xff0c;特…

爬虫第四篇:Xpath 路径表达式全解析:从网页基础到爬取百度贴吧图片实战

简介&#xff1a;本文围绕 Xpath 路径表达式展开讲解&#xff0c;先是介绍了网页相关基础如 html、css、vue 以及前后端分离的概念与示例&#xff0c;包括各部分的结构、作用及简单代码展示&#xff0c;随后详细阐述了 xml 的节点关系、选取节点、谓语等理论知识&#xff0c;最…

使用lumerical脚本语言创建弯曲波导并进行数据分析(纯代码实现)

本文使用lumerical脚本语言创建弯曲波导、设置有限差分时域(FDTD)模拟、改变波导弯曲半径计算损耗、绘制图像展示电场强度分布情况及对具有不同弯曲半径的波导进行一系列模拟和分析操作(代码均有注释讲解)。 一、创建弯曲波导 1.1 基本结构讲解 (1)包层(Clad) 在波导结…

HarmonyOS4+NEXT星河版入门与项目实战(23)------实现手机游戏摇杆功能

文章目录 1、案例效果2、案例实现1、代码实现2、代码解释4、总结1、案例效果 2、案例实现 1、代码实现 代码如下(示例): import router from @ohos.router import {ResizeDirection } from @ohos.UiTest import curves

Redis面试专题-持久化

前言 开始Redis面试知识的复习和资料的收集&#xff08;收集和参考了网上的优质文章&#xff09;&#xff0c;本篇文章会不断更新&#xff0c;本系列文章主要分为两部分&#xff0c;一部分是该专题所涉及的相关基础知识&#xff0c;另一部分是面试题与思考题&#xff0c;大部分…

Blender导入下载好的fbx模型像的骨骼像针戳/像刺猬

为什么我下载下来的骨骼模型和我自己绑定的模型骨骼朝向完全不一样 左边是下载的模型 右边是我自己绑定的模型 左边的模型刚刚感觉都是像针一样往外戳的&#xff0c;像刺猬一样那种。 解决方法勾选自动骨骼坐标系

Ubuntu22.04上kdump和crash的使用

0.前言 1.引用&#xff1a; 解决Linux内核问题实用技巧之 - Crash工具结合/dev/mem任意修改内存-腾讯云开发者社区-腾讯云 解决Linux内核问题实用技巧之-dev/mem的新玩法-腾讯云开发者社区-腾讯云 ubuntu内核转储分析——kdump和crash的下载和使用_ubuntu kdump-CSDN博客 U…

linux安全-firewalld防火墙-基础讲解

目录 一、 防火墙技术分类 二、 firewalld 三、 firewalld支持的类型的NAT 四、 富语言 五、 firewalld配置方式 六、 firewall-cmd命令 七、 小实验 这篇文章将对 firewalld 防火墙的基础知识进行介绍 firewalld简介&#xff1a;firewalld的作用是为包过滤机制提供匹配…

Android中使用NSD扫描,实现局域网内设备IP的发现

0. 前言 本文介绍了什么是NSD协议&#xff0c;并介绍了如何在Android中实现NSD的服务端和客户端&#xff0c;实现局域网内的设备发现功能。 1. NSD是什么 在Android开发中&#xff0c;NSD&#xff08;Network Service Discovery&#xff09;是一种用于在局域网内发现其他设备…

ROS2 系列学习教程(总目录)

ROS2Learning ROS1 系列学习教程(总目录) 一、ROS2 简介 1.1 ROS2简介及学习资源汇总 二、ROS2 基础 2.1 ROS2安装详细教程&#xff08;以Humble为例&#xff09; 2.2 ROS2 构建系统 colcon 介绍、安装与使用 2.3 ROS2 与 ROS1 编码方式对比 ROS2 与 ROS1 编码方式对比&am…

万字长文解读深度学习——VQ-VAE和VQ-VAE-2

&#x1f33a;历史文章列表&#x1f33a; 深度学习——优化算法、激活函数、归一化、正则化 深度学习——权重初始化、评估指标、梯度消失和梯度爆炸 深度学习——前向传播与反向传播、神经网络&#xff08;前馈神经网络与反馈神经网络&#xff09;、常见算法概要汇总 万字长…

Vue 组件通信全面解析

Vue 组件通信全面解析&#xff1a;方式、原理、优缺点及最佳实践 在 Vue 开发中&#xff0c;组件通信是一个重要的核心问题。随着应用复杂度的增加&#xff0c;如何在组件之间有效传递数据、触发事件&#xff0c;直接影响代码的可维护性和可扩展性。Vue 提供了多种组件通信方式…