C语言-3

定义指针

/*指针的概念:1.为了方便访问内存中的内容,给每一个内存单元,进行编号,那么我们称这个编号为地址,也就是指针。2.指针也是一种数据类型,指针变量有自己的内存,里面存储的是地址,也就是那些编号。四要素1.指针本身的类型    例如:float*    int*    ...2.指针指向的类型    例如:float        int        ...3.指针本身的内存4.指针指向的内存运算符*:1.定义指针时,通过 * 符号,来表示定义的是一个指针,并且是指针自身的类型的组成部分2.其他时候,表示解析引用(取内容:通过内存编号,读取内存中的内容)&:取(首)地址符,作用:取出(内存的)首地址
*/# include <stdio.h>int main()
{// 定义指针(指针:pointer)float* p_name;    // 指针本身的类型:float*    指针指向的类型:floatint * p1;int *p2;        // * 符号偏不偏移不影响其功能return 0;
}

指针初始化与赋值

/*知识储备:// 初识化:定义的同时,给值int a = 0;// 赋值:先定义,再给值int b;b = 0;
*/# include <stdio.h>int main()
{    // 初始化int num = 6;int val = 8;// 初始化int* p1 = &num;    // 对于指针变量p1,如果进行给值,必须给地址(内存编号)// 赋值int* p2;p2 = &val;// 自行体会int* p3 = p1;// 直接存入地址(不推荐使用,因为你不知道自己随便写的地址里面是什么!!)int* p4 = (int*)123456;    // 将 整型123456 强转为 int*类型 的“地址”int* p5 = (int*)0XAB25;    // 计算机中的内存地址通常用16进制数表示// 直接使用地址:置空(即:"使用0地址,NULL:0X0")int* p6 = NULL;    // 等价于 int* p6 = (int*)0X0;// 目的:为了给暂无指向的指针,提供指向,保证安全,将内存中的0地址特殊化// 数组名就是数组的首地址int arr[3] = { 1, 2, 3 };// 数组类型:int [3]// 元素类型:int// arr 类型:int*int* p7 = arr;return 0;
}

探究内存

/*1.变量在内存中所占的字节数所有的指针变量,不论类型,在内存中所占的字节数都是一样的,都是4个字节(或者8个字节)(8个字节是因为时代的发展,部分好的计算机性能得到提升,一般都是4个字节)2.指针本身的内存,以及指针指向的内存指针本身的内存:4个字节(指针变量只需要存储,所指向的变量的首地址)指针指向的内存:看你所指向的类型,视情况而定
*/# include <stdio.h>int main()
{    double num = 12.0;double* p1 = &num;printf("%f \n", num);printf("%f \n", *p1);    // 利用指针,取得 num 的值return 0;
}

在这里插入图片描述

指针的偏移

在这里插入图片描述

  • 大端模式与小端模式:前往学习

内存区域划分-基础

/*
内存区域的划分
四个:常量区,栈区,堆区,静态全局区
五个:常量区,栈区,堆区,静态全局区,代码区1.代码区:存代码
2.常量区:存常量
3.静态全局区:静态(static)变量,全局变量
4.栈区:普通局部变量
5.堆区:由程序员手动申请,手动释放
*/# include <stdio.h>int a;                // 普通“全局”变量(初识值默认为零)
// 作用域:当前项目
// 生命周期:程序开始到结束static int b;        // 静态“全局”变量(初识值默认为零)
// 作用域:当前文件
// 生命周期:程序开始到结束int main()
{    int c;            // 普通局部变量(无初始值)// 作用域:当前语块// 生命周期:当前语块static int d;    // “静态”局部变量(初识值默认为零)// 作用域:当前语块// 生命周期:程序开始到结束return 0;
}
# include <stdio.h>void func()
{static int num;        // 只会定义一次printf("%d \n", num);num++;printf("%d \n", num);}int main()
{    func();func();func();return 0;
} /*运行结果:011223请按任意键继续. . .
*/

空类型指针

/*void* 指针1.不能自增自减2.不能偏移3.不能读取内容但是!可以接收任何类型的指针而不需要强转类型可以利用这个特点,将 void* 指针当作通用的存放地址的“容器”e.g.int a = 6,b = 8.8;int* p1 = &a;double* p2 = &b;void* p0 = NULL;    // 当作存放“内存地址”的容器使用p0 = p1;p0 = p2;...*/# include <stdio.h>int main()
{    void* p0 = NULL;return 0;
}

简单开辟内存

/*简单开辟内存1.申请---有两个函数能够实现申请内存的功能:A. malloc(参数:需要字节的总数);B. calloc(参数:每个需要的字节数,个数);返回值都是 void* 类型的指针2.使用3.释放free(参数:首地址)如果不释放的话,会导致“内存泄露”4.置空如果不置空的话,会出现“野指针”
*/# include <stdio.h>int main()
{    /* malloc */double* p = (double*)malloc(sizeof(double));    // 申请一个double类型大小的内存(8字节)*p = 3.14;    // 使用printf("%lf \n", *p);free(p);    // 通过 p 里面存储的首地址,找到相对应的内存,从这里开始释放,一直释放到,申请内存的时候,做了标记的地方p = NULL;    // 通过置空,让指针不再指向已经被释放掉的内存/* calloc */float* p1 = (float*)calloc(sizeof(float),1);*p1 = 3.14f;printf("%f \n", *p1);free(p1);p1 = NULL;printf("进阶运用 \n");// 进阶运用p = (double*)malloc(sizeof(double)*10);    // 申请10个 double 类型大小的连续的内存(补充:因为上面将p定为 double* 而且置空过了,所以可再度利用)for (int i = 0; i < 10; i++ ){    *(p + i) = 10 + i;    // 给值printf("%lf \n", *(p + i));    // 展示值}free(p);p = NULL;/*对于上面 for 循环部分的补充:p:里面存的是:申请的内存的首地址在一次申请中,申请的内存是连续的*(p + i) <===> p[i]        // 注意!它不是数组!*/return 0;
}
# include <stdio.h>int main()
{    // 指针布局int row = 3;int** pp = (int**)calloc(sizeof(int*), row);int len = 4;for (size_t i = 0; i < row; i++)    // size_t是什么?点我跳转学习{pp[i] = (int*)calloc(sizeof(int), len);}// 内容展示for (size_t i = 0; i < row; i++){for (size_t j = 0; j < len; j++){    pp[i][j] = i * 10 + j;    // 给值printf("%-5d", pp[i][j]);    // 展示值,注意!这里不是二维数组!(看不懂请回顾上页内容)}printf("\n");}// 释放内存for (size_t i = 0; i < row; i++){free(pp[i]);pp[i] = NULL;}free(pp);pp = NULL;return 0;
}

自动扩容

# include <stdio.h>int main()
{    int len = 5;    // 默认长度int* p = (int*)calloc(sizeof(int), len);int num = 1;for (size_t i = 0; num != 0; i++)    // 用户不输入0结束,就一直获取数据并复制到开辟的内存中{scanf("%d", &num);p[i] = num;        // 数据复制到开辟的内存中}for (size_t i = 0; p[i] != 0; i++){printf("%-5d", p[i]);    // 展示数据}free(p);p = NULL;return 0;
}
/*扩容的本质是:将小内存中的所有内容拷贝到大内存中,然后,再继续对大内存进行别的操作
*/# include <stdio.h>int main()
{    // 长度int len = 5;// 首次申请内存int* p = (int*)calloc(sizeof(int), len);int* temp = p;    // 成为p的分身,以防万一// 重复输入数据(并复制到内存中)int num = 1;int i = 0;while (scanf("%d", &num), num != 0){if (i < len)    // 没满的情况下{temp[i++] = num;    // 存完一次,记录一下}else   // 满了的情况下{len += 5;p = (int*)calloc(sizeof(int), len);        // 重新申请更大的内存for (int j = 0; j < i; j++){p[j] = temp[j];}free(temp);temp = NULL;temp = p;    // 继续成为当前p的分身temp[i++] = num;}}// 输出数据printf("--------------------\n");for (int j = 0; j != i; j++){printf("%d \n", temp[j]);}free(p);p = NULL;temp = NULL;return 0;
}

内存区域划分-进阶

/*内存区域的划分1.代码区存储代码2.常量区存储常量3.全局区(静态全局区)存储: 1.静态变量    2.全局变量# include <stdio.h>int c;            // 普通全局变量static int d;    // 静态全局变量int main(){int a;            // 普通局部变量static int b;    // 静态局部变量int c;    // 注意这个c不是上面的c,它们只是名字看起来一样而已a = 10;        // 普通局部变量没有默认初始值,所以需要自己赋值printf("a = %d \n", a);printf("b = %d \n", b);printf("c = %d \n", c);printf("d = %d \n", d);// 通过以上 printf,可以总结规律:静态全局区,默认的初始值为0// 作用域和生命周期作用域            生命周期普通全局变量        当前项目        程序开始到程序结束静态全局变量        当前文件        程序开始到程序结束普通局部变量        当前语块        当前语块静态局部变量        当前语块        程序开始到程序结束return 0;}4.栈区存储:普通局部变量从定义时系统自动分配内存,离开当前语块系统就会自动回收内存 5.堆区由程序员手动申请和释放
*/

指针与函数

/*1.指针函数返回值类型是指针的函数2.函数指针指向函数的指针
*/
// 1.指针函数// 下面的代码是一个错误的例子,你能发现它的错误吗?
# include <stdio.h>int* test();    // 声明int main()
{    int* temp = test();printf("%d \n", *temp);return 0;
} int* test()
{int num = 10;int* p = &num;return p;    // 返回了栈区变量的首地址(非常严重的问题!详情见下)
}/*下面的内容是在栈区,当运行完毕,系统会回收其内存资源:int* test(){int num = 10;int* p = &num;return p;}当函数返回栈区变量 num 的内存地址之后,函数运行完毕,系统回收 num 内存,供以后"某某东西"使用所以,返回的地址不但没有作用,还会导致以后非法访问内存的问题出现*/
// 2.函数指针/*函数指针的定义返回类型说明符 (*函数指针变量名)(参数列表);
*/# include <stdio.h>int func();    // 声明int main()
{    // 定义函数指针,并进行初始化int(*p)() = func;    // 即:定义了指针p,而且 p 等于 func(func里面存的是函数的首地址)func();p();return 0;
}int func()
{printf("成功执行了 func 函数!\n");return 6;
}
// 函数指针,知识扩展1# include <stdio.h>int func();    // 声明typedef int funcType();    // 将 int...() 取别名为 funcTypeint main()
{    funcType* p = func;p();return 0;
}int func()
{printf("成功执行了 func 函数!\n");return 6;
}
// 函数指针,知识扩展2# include <stdio.h>int func(int a, int b);    // 声明typedef int(*pfunc)(int a, int b);int main()
{    pfunc p = func;        // 这样也能定义函数指针int res = p(1,2);printf("%d \n", res);return 0;
}int func(int a, int b)
{printf("成功执行了 func 函数!\n");return a + b;
}

指针与数组

/*1.指针数组......2.数组指针......
*/
// 1.指针数组/*# include <stdio.h>int main()
{    // 定义并初始化"数组"int arr1[3] = { 1, 2, 3 };    // 数组 arr1[3] -> 里面存的都是 int 类型// 定义并初始化"指针数组"int* arr2[3] = { 地址1,地址2,地址三 };    // 数组 arr2[3] -> 里面存的都是 int* 类型arr2[2] = 新地址;return 0;
} */
// 2.数组指针/*定义"数组"指针:所指向的数组里面存的数据类型 (*数组指针名称)[所指向的数组的长度];
*/# include <stdio.h>int main()
{    int arr[3] = { 1, 2, 3 };    // 建立一个数组。
//    arr 里面存的是数组内存的首地址,而 [] 表示内存里面存的那一堆东西是数组,3 表示数组长度,int 表示数组里面存的数据是 int 类型int(*p)[3];    // 长度为 3 的数组指针p = arr;printf("%d \n", p[1]);return 0;
}
// 数组指针,知识扩展# include <stdio.h>typedef int(*pType)[3];    // 定义类型:int(*pType)[3],取别名为:pTypeint main()
{    int arr[3] = { 1, 2, 3 };pType p;    // 变量 p 的类型为 pType,而属于这种类型的变量 p 必然满足 int(*pType)[3] 模板格式p = arr;    // arr里面储存的“数组的内存首地址”复制给变量 pprintf("%d \n", (*p)[0]);    // 注意!不要写成 p[0],虽然 p 获得了 arr 里面存的首地址,但是 *p 才是代表数组整体return 0;
} /*同理:# include <stdio.h>typeof int pArr[3];int main(){int arr[3] = { 1, 2, 3 };pArr p;p = arr;}
*/

使用const修饰指针

/*const:常量,被它修饰的变量会具有常量的属性,使用 const 修饰指针包含三种情况1.常量指针(指向常量的指针)指向常量的指针 type const *p; 或者 const type *p;可以改变指向,但是不能用 *p 修改指向变量的值2.指针常量它是常量,本身不能改变,也就是不能改变指向因为指向不能改,所以必须初始化但是可以通过取内容修改指向的内存中的内容3.常量指针常量("常量指针"常量即:指针常量)指针本身是一个常量,指向的也是常量const int * const p = &a;不能改变指向,也不能改变指向的内存的内容
*/# include <stdio.h>int main()
{const int num = 0;    // 变量 num 使用 const 修饰了就不能被修改了// 1.常量指针int a = 0, b = 9;const int * p = &a;        // const -> intp = &b;    // 可以改变指向// 2.指针常量int c = 6;int* const p1 = &c;        // const -> p1*p1 = 10;    // 可以修改内容// 3.常量指针常量int d = 8;const int* const p = &d;    // const -> int 和 preturn 0;}

指针和结构体

/*指针与结构体:指针与结构体结合起来使用包含两种情况:一.指针成员结构体变量的成员中存在指针二.结构体指针指向结构体变量的指针
*/
// 指针成员# include <stdio.h>typedef struct
{int n;int m;int* p;    // 定义指针}MyStruct;int main()
{MyStruct mystr;mystr.n = 0;mystr.m = 0;mystr.p = NULL;    // 地址置空return 0;}
// 结构体指针# include <stdio.h>typedef struct
{int n;int m;}MyStruct;int main()
{MyStruct mystr;mystr.n = 0;mystr.m = 0;MyStruct* p = NULL;    // 定义一个指针 p ,它的类型是 MyStruct*,即该指针指向的是有 MyStruct 类型的变量(首地址)p = &mystr;    // mystr 便符合条件,可以将首地址 &mystr 赋值给 p// 注意!通过指针访问“结构体中的元素”的时候,用 -> 符号,而不是用 . 符号p->n = 9;p->m = 8;return 0;}

使用指针的注意事项

/*注意事项1.避免野指针推荐:每次定义指针都进行初始化(有指向就给指向,没指向就置空 )2.注意类型匹配3.防止内存泄漏只有堆区是自己申请,自己释放,其他地方都是系统分配,系统回收总结:指针能够直接操作内存,必须在自己明确用途的情况下使用,否则很可能会造成严重后果!
*/

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

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

相关文章

【HarmonyOS应用开发】APP应用的通知(十五)

相关介绍 通知旨在让用户以合适的方式及时获得有用的新消息&#xff0c;帮助用户高效地处理任务。应用可以通过通知接口发送通知消息&#xff0c;用户可以通过通知栏查看通知内容&#xff0c;也可以点击通知来打开应用&#xff0c;通知主要有以下使用场景&#xff1a; 显示接收…

BUGKU-WEB Simple_SSTI_1

02 Simple_SSTI_1 题目描述 没啥好说的~ 解题思路 进入场景后&#xff0c;显示&#xff1a; You need pass in a parameter named flag。ctrlu 查看源码 <!DOCTYPE html> <html lang"en"> <head><meta charset"UTF-8"><titl…

代码随想录 Leetcode491. 非递减子序列

题目&#xff1a; 代码(首刷看解析 2024年2月3日&#xff09;&#xff1a; class Solution { private:vector<vector<int>> res;vector<int> path; public:void backtracking(vector<int>& nums, int startIndex) {if (path.size() > 1) {res.…

HSM加密机原理:密钥管理和加密操作从软件层面转移到物理设备中 DUKPT 安全行业基础8

HSM加密机原理 硬件安全模块&#xff08;HSM&#xff09;是一种物理设备&#xff0c;设计用于安全地管理、处理和存储加密密钥和数字证书。HSM广泛应用于需要高安全性的场景&#xff0c;如金融服务、数据保护、企业安全以及政府和军事领域。HSM提供了一种比软件存储密钥更安全…

Web html和css

目录 1 前言2 HTML2.1 元素(Element)2.1.1 块级元素和内联(行级)元素2.1.2 空元素 2.2 html页面的文档结构2.3 常见标签使用2.3.1 注释2.3.2 标题2.3.3 段落2.3.4 列表2.3.5 超链接2.3.6 图片2.3.7 内联(行级)标签2.3.8 换行 2.4 属性2.4.1 布尔属性 2.5 实体引用2.6 空格2.7 D…

vue3 之 组合式API—生命周期函数

vue3的生命周期API 生命周期函数基本使用 1️⃣导入生命周期函数 2️⃣执行生命周期函数 传入回调 <scirpt setup> import { onMounted } from vue onMounted(()>{// 组件挂载完毕mounted执行了 }) </script>执行多次 生命周期函数是可以执行多次的&#xff…

支持多字体、静动态的.NET图片验证码的开源项目

上次分享过 SkiaSharp 这个开源图形项目&#xff0c;并举了一个生成验证码的例子&#xff0c;具体见文章&#xff1a;《SkiaSharp&#xff1a;.NET强大而灵活的跨平台图形库》。 但文中验证码比较简单&#xff0c;刚好看到一个非常不错的图片验证码&#xff0c;分享给大家。 …

ChatGPT之搭建API代理服务

简介 一行Docker命令部署的 OpenAI/GPT API代理&#xff0c;支持SSE流式返回、腾讯云函数 。 项目地址&#xff1a;https://github.com/easychen/openai-api-proxy 这个项目可以自行搭建 OpenAI API 代理服务器工具&#xff0c;该项目是代理的服务器端&#xff0c;不是客户端。…

MySQL 用户管理

重点&#xff1a; 视图&#xff0c;函数&#xff0c;存储过程&#xff0c;触发器&#xff0c;事件&#xff08; 了解 &#xff09; 用户管理&#xff0c;密码管理 grant revoke 权限管理 MySQL 架构&#xff08; 了解 &#xff09; 存储引擎&#xff1a;MyISAM 和 InnoDB …

【JavaScript 漫游】【008】错误处理机制

文章简介 本文为【JavaScript 漫游】专栏的第 008 篇文章&#xff0c;记录了笔者所学习到的错误处理机制的所有知识点。 Error 实例对象原生错误类型&#xff0c;包括 SyntaxError、ReferenceError、RangeError、TypeError、URIError对象自定义错误throw 语句try...catch 结构…

【iOS ARKit】3D人体姿态估计实例

与2D人体姿态检测一样&#xff0c;在ARKit 中&#xff0c;我们不必关心底层的人体骨骼关节点检测算法&#xff0c;也不必自己去调用这些算法&#xff0c;在运行使用 ARBodyTrackingConfiguration 配置的 ARSession 之后&#xff0c;基于摄像头图像的3D人体姿态估计任务也会启动…

Python中的HTTP代理与网络安全

在当今数字化的世界里&#xff0c;网络安全已经成为我们无法忽视的重要议题。无数的信息在网络上传递&#xff0c;而我们的隐私和敏感数据也在这个过程中可能面临被窃取或滥用的风险。在Python编程中&#xff0c;HTTP代理作为一种工具&#xff0c;能够在网络安全方面发挥重要的…

docker重建镜像

DockerFile如下&#xff1a; FROM k8s-registry.qhtx.local/base/centos7-jdk8-haitong0704RUN yum -y update && yum install -y python3-devel && yum install -y python36 RUN mv /usr/bin/python /usr/bin/python_old RUN ln -s /usr/bin/python3 /usr/bi…

虹科技术|一文详解IO-Link Wireless技术如何影响工业无线自动化

导读&#xff1a;在工业无线自动化的飞速发展进程中&#xff0c;IO-Link Wireless技术成为了一项具有颠覆性的创新。它将IO-Link协议与无线连接完美结合&#xff0c;解决了传统通信技术在工业应用中的痛点。本文将深入解析IO-Link Wireless技术的原理、应用领域、优势以及实际案…

小华和小为的聚餐地点 - 华为OD统一考试

OD统一考试(C卷) 分值: 200分 题解: Java / Python / C++ 题目描述 小华和小为是很要好的朋友,他们约定周末一起吃饭。 通过手机交流,他们在地图上选择了多个聚餐地点(由于自然地形等原因,部分聚餐地点不可达)。 求小华和小为都能到达的聚餐地点有多少个? 输入描述…

[晓理紫]每日论文分享(有中文摘要,源码或项目地址)--强化学习、模仿学习、机器人

专属领域论文订阅 关注{晓理紫|小李子}&#xff0c;每日更新论文&#xff0c;如感兴趣&#xff0c;请转发给有需要的同学&#xff0c;谢谢支持 如果你感觉对你有所帮助&#xff0c;请关注我&#xff0c;每日准时为你推送最新论文。 为了答谢各位网友的支持&#xff0c;从今日起…

WINDOWS搭建NFS服务器

下载并安装 Networking Software for Windows 启动配置 找到安装目录&#xff08;如C:\Program Files\nfsd&#xff09;&#xff0c;双击nfsctl.exe&#xff0c;菜单Edit->Preferences 启动后&#xff1a; 配置Export Exports->Edit exports file 其他的几句我都删除…

XML:可扩展标记语言

XML&#xff1a;可扩展标记语言 主要内容 XML介绍DTDXSDDOM解析SAX解析 学习目标 知识点要求XML介绍掌握DTD掌握XSD掌握DOM解析掌握SAX解析掌握 一、XML介绍 1. 简介 XML&#xff08;Extensible Markup Language&#xff09;可扩展标记语言。严格区分大小写。 2. XML和…

react将选中本文自动滑动到容器可视区域内

// 自动滚动到可视区域内useEffect(() > {const target ref;const wrapper wrapperRef?.current;if (target && wrapperRef) {const rect target.getBoundingClientRect();const wrapperRect wrapper.getBoundingClientRect();const isVisible rect.bottom &l…

RPM与YUM

RPM RPM是Red Hat Package Manager的缩写&#xff0c;它是一种用于安装、卸载、升级和管理RPM包的工具。RPM使用一种数据库记录的方式来将软件安装到Linux系统&#xff0c;可以自动解决依赖性问题&#xff0c;并且提供了查询和校验等功能。 以下是使用rpm的基本操作&#xff…