学习C指针

指针基本介绍

计算机中的每个内存都有地址

整型分配4字节,字符分配1字节 ,浮点数分配4字节

指针是一个变量,它存放着另外一个变量的地址

int a;
int *p;
p = &a;//
a = 5;
printf(p)  //get a address
print &a   //get a address
print &p   //get p address
print *p   //得到指针所指向的地址的值p = address*p = value at address

 当指针变量前面没有加*号进行操作,是在对地址进行操作,

*p则是对指针所指向的地址操作

指针代码示例

#include<stdio.h>
#include<stdlib.h>
int main()
{int a = 10;int *p = &a;//p = &a;//&a = address of a//int* p 意外着指向整型的指针然后写出变量名printf("Address of p is %d\n",p);printf("Value at p is %d\n",*p);printf("%d\n",p);printf("%d\n",*p);//*p = value at address pointed by pprintf("%d\n",&a);printf("a = %d\n",a);*p = 12;//使用指针对所指向的地址值进行修改printf("a = %d\n",a);int b = 20;*p = b;printf("Address of p is %d\n",p);printf("Value at p is %d\n",*p);system("pause");return 0;
}
#include <stdio.h>
#include <stdlib.h>int main() {int a = 10;int *p;p = &a;//Pointer arithmeticprintf("Address p is %d\n",p);printf("value at address p is %d\n",*p);printf("size of integer is %d bytes\n",sizeof(int));printf("Address p+1 is %d\n",p+1); //增加4字节以得到下一个整型的地址system("pause");return 0;
}

 指针的类型,算术运算,void指针

指针是强类型

我们需要一个特定类型的指针变量来存放特定类型变量的地址 

byte3byte2byte1byte0
00000000000000000000010000000001
203202201200
最左边为符号位2的10次方2的一次

剩下的31个位用来存储值

#include <stdio.h>
#include <stdlib.h>int main() {int a = 1025;int *p;p = &a;//Pointer arithmeticprintf("size of integer is %d bytes\n",sizeof(int));printf("Address = %d,value = %d\n",p,*p);char *po;po = (char*)p;printf("size of char is %d bytes\n",sizeof(char));printf("Address = %d,value = %d\n",po,*po);printf("Address = %d,value = %d\n",po+1,*(po+1));system("pause");return 0;
}

 通用指针类型,不针对某个特定的数据类型,这种指针类型被称为void类型的指针

void *p

指向指针的指针(pointer to pointer)

#include <stdio.h>
#include <stdlib.h>int main() {int x = 5;int *p = &x;*p = 6;int **q = &p;int ***r = &q;printf("%d\n",*p);//指针p所指向的内存地址的值printf("%d\n",*q);//指针q所指向的指针p的地址printf("%d\n",*(*q));//指针q所指向的指针q的地址,指针p所指向的地址值printf("%d\n",*(*r));printf("%d\n",*(*(*r)));//变量x是整型,为了得到x的地址,需要int* 类型的指针//为了存储p地址,需要一个指向int*类型的指针,为此再加一个*,表示这个指针指向的是int*//可以无限套娃system("pause");return 0;
}

函数传值vs传引用

当我们在函数里面声明一个变量,我们把它叫做局部变量,我们只能在声明了变量的地方使用这个变量

#include<stdio.h>
#include<stdlib.h>void Increment(int a)
{a = a + 1;printf("Address of variable a in increment = %d\n",&a);
}int main()
{int a;a = 10;Increment(a);printf("Address of variable a in main = %d\n",&a);system("pause");return 0;
}

main函数的a与自增函数的a的地址不一样

应用程序所使用的内存如下表格 

内存
Heap
Stack
Static/Global
Code(Text)

第一部分(Code):用来存储程序的指令,计算机需要把指令加载到内存,就像上面程序中的自增语句

第二部分:分配给静态或者全局变量

如果我们不是在函数中声明变量,那么它将会是一个全局变量(Global),作为一个全局变量,在程序的任何地方都可以访问和修改。

局部变量只能在特定的函数或者特定的代码块进行访问和修改。

第三部分:局部变量都放在stack部分

第四部分:堆

内存中的四个部分,一二三是固定的,应用程序在运行时可以要求在堆区为它分配跟多的内存

当我们在主函数中调用其它函数,这个参数被称为实参,被调函数中的参数被称为形参,调用时,实参被映射到形参

传引用

#include<stdio.h>
#include<stdlib.h>void Increment(int *p)
{*p = (*p) + 1;
}int main()
{int a;a = 10;Increment(&a);printf("a = %d\n",a);system("pause");return 0;
}

指针和数组

#include<stdio.h>
#include<stdlib.h>int main()
{int A[] = {2,4,5,8,1};printf("%d\n",A);printf("%d\n",&A[0]);printf("%d\n",A[0]);printf("%d\n",*A);system("pause");return 0;
}
#include<stdio.h>
#include<stdlib.h>int main()
{int A[] = {2,4,5,8,1};int i;for(i = 0;i < 5;i++){printf("Address = %d\n",&A[i]);printf("Address = %d\n",A+i);printf("Value = %d\n",A[i]);printf("value = %d\n",*(A+i));}system("pause");return 0;
}

数组作为函数参数

#include<stdio.h>
#include<stdlib.h>int SumOfElements(int A[],int size)
{int i,sum = 0;for(i = 0;i < size;i++){sum+= A[i];}return sum; 
}int main()
{int A[] = {1,2,3,4,5};int size = sizeof(A)/sizeof(A[0]);//用数组A的大小除以A[0]的大小,这样就会得到数组中元素的个数int total = SumOfElements(A,size);printf("Sum of elements = %d\n",total);system("pause");return 0;
}
#include<stdio.h>
#include<stdlib.h>int SumOfElements(int A[])//A是一个整型指针,而在main函数中A是一个数组
{int i,sum = 0;int size = sizeof(A)/sizeof(A[0]);printf("SOE - Size of A = %d,size of A[0] = %d\n",sizeof(A),sizeof(A[0]));//'sizeof' on array function parameter 'A' will return size of 'int*' //当编译器看到数组作为函数参数的时候,它不会拷贝整个数组,这里我们不是拷贝变量的值,而仅仅是拷贝变量的地址for(i = 0;i < size;i++){sum+= A[i];}return sum; 
}int main()
{int A[] = {1,2,3,4,5};//用数组A的大小除以A[0]的大小,这样就会得到数组中元素的个数int total = SumOfElements(A);printf("Sum of elements = %d\n",total);printf("Main - Size of A = %d,size of A[0] = %d\n",sizeof(A),sizeof(A[0]));system("pause");return 0;
}

指针和字符数组

NULL字符的ASCII的值是0,因为C里面的字符串必须以NULL结束

#include<stdio.h>
#include<stdlib.h>int main()
{char C[5];C[0] = 'J';C[1] = 'O';C[2] = 'H';C[3] = 'N';C[4] = '\0';printf("%s",C);getchar();return 0;
}

strlen函数不会把null算入在内

当把字符数组赋值给字符指针,实际上是把字符数组的首地址告诉指针

#include<stdio.h>
void print(char* C)
{int i = 0;while(C[i] != '\0'){printf("%c",C[i]);i++;}printf("\n");
}
int main()
{char C[20] = "Hello";print(C);getchar();return 0;
}

指针和二维数组

指针和多维数组

多维数组本质上是数组的数组

数组基本上可以理解为同类型事物的集合,多维数组基本上可以理解为数组的集合

当仅使用数组名的时候,它会返回数组首元素的指针

print B //400

print *B //400

print B[0] //400

print &B[0][0] //400

B返回一个指向一维数组的指针,而*B返回一个指向整型的指针 

当我们只是打印地址的时候,一维数组B[0]和B[0]的首元素的起始地址是一样的,所以会打印相同的地址

arr[2][3][4],相当于一个三维数组有两个数组,这两个二维数组里面各自有三个数组,这三个数组各自里面再有四个数组

解引用就是 当前变量存取的值,如果*p是指向数组,则值就是首地址,如果是指向数据,则就是值。

#include<stdio.h>
#include<stdlib.h>
int main()
{int C[3][2][2]={{{2,5},{7,9}},{{3,4},{6,1}},{{0,8},{11,13}}};printf("%d %d %d %d",C,*C,C[0],&C[0][0]);printf("%d\n",*(C[0][0]+1));system("pause");return 0;
}

多维数组作为参数传给函数

指针和动态内存-栈vs堆

栈,用来存放函数调用的所有信息和所有局部变量

局部变量是在函数内部声明的,只在函数执行期间存活

不在函数中声明的变量,它们的生命周期贯穿整个应用程序

任何时候都是栈顶的函数在执行

应用程序的堆不是固定的,它的大小在应用程序的整个声明周期是可变的

这里所说的堆和数据结构中的堆没有关系,此处的堆只是用来描述空闲的内存池

栈也是一种数据结构,但是栈区实际上就是栈这种数据结构的一种实现,堆并不是这样

内存在栈上的分配和销毁有一定的规则 ,当一个函数被调用的时候,它被压入堆栈,当它结束的时候,弹出堆栈。

如果变量是在栈上分配的,我们不能操作变量的范围

不能操控变量的范围,就是比如说定义了一个可变数组在栈中,而在程序运行中栈的内存不会增长,因此你的数组很有可能因为长度过长而造成栈溢出

应用程序的堆不是固定的,它的大小在应用程序的整个声明周期是可变的,也没有特定的规则来分配和销毁相应的内存

堆也被称为动态内存,使用堆内存意味着动态内存分配

堆也是一种数据结构,但是与c中的堆不一样

任何使用malloc分配的内存,最终通过调用free进行释放

c++用new来代替malloc ,delete来代表free

指针和动态内存

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

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

相关文章

chatgpt免费使用的网站

前言 如果您认为本文对你有帮助&#xff0c;希望可以点赞收藏&#xff01;感谢您的支持 下面我为你推荐我自己在用的gpt类工具&#xff0c;帮你在工作学习生活上解决一些大小问题 &#x1f389;智能GPT 地址&#xff1a; https://meet.adminjs.net 在他的详情中有详细的使用…

ubuntu18.04.6 搭建mqtt服务器emqx 之docker方式

ubuntu18.04.6 搭建mqtt服务器emqx 之docker方式 前提docker环境已经安装好 如未安装&#xff0c;请参考博文https://blog.csdn.net/a554521655/article/details/134251763 文章目录 ubuntu18.04.6 搭建mqtt服务器emqx 之docker方式安装emqx查看是否安装并启动成功登录前端查 安…

FastAdmin西陆教育系统(xiluEdu)开源代码

应用介绍 一款基于FastAdminThinkPHPUniapp开发的西陆教育系统&#xff08;微信小程序、移动端H5、安卓APP、IOS-APP&#xff09;&#xff0c;以下是教育系统所包含的一些功能&#xff1a; 视频课程&#xff1a;教育系统提供在线视频课程&#xff0c;学生可以通过网络观看教师…

每日一题——LeetCode1154.一年中的第几天

方法一 列举法&#xff1a; 用一个数组把每个月份的天数都列举出来 判断闰年&#xff0c;是闰年2月份有29天 循环对当前月份之前的月份天数求和 加上当天月份的天数 var dayOfYear function(date) {let year date.slice(0, 4);let month date.slice(5, 7);let day dat…

Android 13 辅助屏导航栏不显示问题

问题 在Android 13 上开启辅助屏幕。但是发现辅助屏systemui 导航按 icon没有显示,但是点击对应的区域有作用 分析 可以用 anroid device monitor 工具分析视图 解决 public NavigationBarView(Context context, AttributeSet attrs) {super(context, attrs);//add star…

【一、测试基础】Java基础语法

Java 的用法及注意事项有很多&#xff0c;今天的目标是了解Java基础语法&#xff0c;且能够输出"hello world" 几个基础的概念 对象&#xff1a;对象是类的一个实例&#xff0c;有状态和行为。一只猫是一个对象&#xff0c;猫的状态有&#xff1a;颜色、名字、品种&…

公众号突破2个限制技巧怎么操作?

一般可以申请多少个公众号&#xff1f;目前企业主体只能申请2个公众号&#xff0c;这也意味着想做矩阵公众号的难度提升了。有些公司靠着诸多不同分工的公众号形成一个个矩阵&#xff0c;获取不同领域的粉丝。比如&#xff0c;目前主体为xx旗下公众号&#xff0c;共有30个&…

《动手学深度学习》学习笔记 第9章 现代循环神经网络

本系列为《动手学深度学习》学习笔记 书籍链接&#xff1a;动手学深度学习 笔记是从第四章开始&#xff0c;前面三章为基础知识&#xff0c;有需要的可以自己去看看 关于本系列笔记&#xff1a; 书里为了让读者更好的理解&#xff0c;有大篇幅的描述性的文字&#xff0c;内容很…

【自控实验】1. 线性系统串联超前校正实验

本科课程实验报告&#xff0c;有太多公式和图片了&#xff0c;干脆直接转成图片了 仅分享和记录&#xff0c;不保证全对 串联超前校正实验&#xff1a;频域设计计算(校正装置)&#xff0c;时域观察验证(校正结果) 使用matlab中的simulink进行仿真

PyCharm中配置安装PyQt5、QtDesigner

PyCharm中配置安装PyQt5 使用 pip install PyQt5 命令安装。 安装pyqt5-tools&#xff1a;pip install pyqt5-tools 安装PyQt5Designer&#xff1a;pip install PyQt5Designer 上述三个都安装好之后&#xff0c;输入 pip list 查看一下 有如下内容就安装成功啦&#xff01;…

【Linux Shell】5. 运算符

文章目录 【 1. 算术运算符 】1.1 expr 命令1.2 [ ] 方括号 【 2. 关系运算符 】【 3. 布尔运算符 】【 4. 逻辑运算符 】【 5. 字符串运算符 】【 6. 文件测试运算符 】 【 1. 算术运算符 】 运算符说明举例赋值a$b 把变量 b 的值赋给 a。 1.1 expr 命令 原生 bash 不支持简…

SpringCloud系列篇:核心组件之熔断器组件

&#x1f973;&#x1f973;Welcome Huihuis Code World ! !&#x1f973;&#x1f973; 接下来看看由辉辉所写的关于SpringCloud的相关操作吧 前言 在微服务架构中&#xff0c;一个应用往往由多个服务组成&#xff0c;这些服务之间相互依赖&#xff0c;依赖关系错综复杂。 例…

C++程序员必备的面试技巧

“程序员必备的面试技巧&#xff0c;就像是编写一段完美的代码一样重要。在面试战场上&#xff0c;我们需要像忍者一样灵活&#xff0c;像侦探一样聪明&#xff0c;还要像无敌铁金刚一样坚定。只有掌握了这些技巧&#xff0c;我们才能在面试的舞台上闪耀光芒&#xff0c;成为那…

经验分享:智能知识库才是数字时代的企业必备选择

随着全球化和竞争的加剧&#xff0c;企业必须通过将知识作为战略资产进行管理&#xff0c;才能保持竞争优势。因此&#xff0c;建设有效的知识库系统&#xff0c;成为了数字时代企业必备的选择。决定企业成功或失败的不再仅仅是产品或服务的质量&#xff0c;而是如何有效利用知…

element-ui 如何修改el-popconfirm的样式

改造之前效果 改造之后效果 代码&#xff1a; <style lang"scss"> .my-popconfirm {width: 92% !important;height: 130px !important;padding: 14px !important;font-size: 28px !important;.el-popper {font-size: 28px !important;}.el-popconfirm__main {…

【RabbitMQ】RabbitMQ高级:如何保证消息可靠性

目录 概述异常捕获机制事务机制持久化存储机制发送端确认机制概述开启发布确认的方法单个发布确认批量发布确认异步发布确认 消费端确认机制消息限流消息幂等性处理 概述 前面学习了如何简单使用RabbitMQ&#xff0c;在实际使用RabbitMQ时&#xff0c;我们还需要考虑很多&…

MySQL-外键等信息

38. 基础-多表查询-概述_哔哩哔哩_bilibili 1、流程函数 2、约束字段 删除外键 &#xff1a; alter table emp2 drop foreign key 外键名 //外键可以保持数据的一致性和完整性&#xff0c;外键的话&#xff0c;就是类似一个主表&#xff0c;一个从表&#xff0c;从表的其中一…

ROS2入门之节点与指令

文章目录 前言一、初识ROS21.ROS简介2.ROS系统框架 二、ROS2创建节点(CPP)1.创建工作空间2.创建功能包3.创建节点4.配置CMakeLists5.编译运行节点&#x1f353;编译节点&#x1f34a;source环境&#x1f34e; 运行节点 报错解决 三、ROS2常用指令1.ros2 pkg create2.ros2 pkg l…

mac 使用brew卸载node

1.查看当前的node版本 node -v 2.查看使用brew 安装的版本&#xff0c;可以看到本机装了14、16、18版本的node brew search node 3.卸载node brew uninstall node版本号 --force 如分别删除14、16、18版本的node命令如下 brew uninstall node14 --force brew uninstall no…

使用AutoDL云计算平台训练并测试Pytorch版本NeRF代码

文章目录 前言一、数据集及代码获取二、租用并设置服务器三、Pycharm远程开发四、训练并测试代码 前言 因为第一次在云服务器上跑代码&#xff0c;所以在这里记录一下。 一、数据集及代码获取 nerf-pytorch项目是 NeRF 的忠实 PyTorch 实现&#xff0c;它在运行速度提高 1.3 倍…