深度解析Linux-C——函数和内存管理

目录

函数指针:

 指针函数:

参数为指针的函数: 

参数为数组的函数:

C语言内存管理

 stdlib.h头文件常用函数介绍

1、局部变量

 2、全局变量

3、 堆空间变量

4、静态变量

5、常量


函数指针:

指向函数的指针,称为函数指针

void   f (int); // 函数 f 的类型是: void (int)
void (*p)(int); // 指针 p 专门用于指向类型为 void (int) 的函数p = &f; // p 指向 f(取址符&可以省略)
p =  f; // p 指向 f// 以下三个式子是等价的:f (666); // 直接调用函数 f
(*p)(666); // 通过索引指针 p 的目标,间接调用函数 fp (666); // 函数指针在索引其目标时,星号可以省略

 指针函数:

指针函数就是返回指针值的函数,本质是一个函数。

//一般定义方法有以下三种格式
int *fun(int x,int y);
int * fun(int x,int y);
int* fun(int x,int y);

一般在申请堆空间的时候函数需要返回一个指针,例如

int *get_memory(int size)
{int *p = malloc(sizeof(int) * size);printf("分配的堆空间地址 %p\n", p);return p;
}

参数为指针的函数: 

函数有形参和实参之分,如何通过形参改变实参呢?

函数的传递分为两种,一种是值传递,一种是地址传递

参数的值传递,形参与实参相互独立互不影响。

参数的地址传递,形参可以通过地址修改实参的数据。(通过函数的地址传递的解引用才能修改实参的数据)

有以下三种情况

#include <stdio.h>void swap(int a, int b)
{int temp = a;a = b;b = temp;printf("swap中a=%d, b=%d\n", a, b);
}int main()
{int a = 100, b = 200;swap(a, b);printf("main函数中a=%d, b=%d\n", a, b);return 0;
}

这是一个简单的交换函数,输出如图

 可以看到在main函数中,函数的值实际上是没有交换的,这就是函数的值传递

第二种情况

#include <stdio.h>void swap_addr(int *a, int *b)
{printf("swap函数中交换之前 a=%p,b=%p\n", a, b);printf("swap函数中交换之前 *a=%d,*b=%d\n\n", *a, *b);int *tmp = a;   // 只是交换了,两个指针所指向的地址而已,并不是交换地址上的内容(数据)!a = b;b = tmp;printf("swap函数中交换之后 *a=%d,*b=%d\n", *a, *b);printf("swap函数中交换之后 a=%p,b=%p\n\n", a, b);
}int main()
{int a = 100, b = 200;printf("main函数中交换之前 &a=%p,&b=%p\n", &a, &b);printf("main函数中交换之前 a=%d, b=%d\n\n", a, b);swap_addr(&a, &b);printf("main函数中交换之后 &a=%p,&b=%p\n", &a, &b);printf("main函数中交换之后 a=%d, b=%d\n", a, b);return 0;
}

输出如图

这种情况虽然是函数的地址传递,但是main函数中的值仍然没有变化,这就是因为我们只对地址进行了交换,没有对地址中的值解引用交换

所以第三种情况时对swap_addr()函数进行修改

void swap_addr_new(int *a, int *b)
{int tmp = *a; *a = *b;*b = tmp;
}

可以看到,main函数中的值被成功修改

参数为数组的函数:

在函数形参为数组时,编译器为了节省内存空间会自动将数组转换为指向数组首地址的指针

如:

int arry_sum(int arry[5]) 等价于 int arry_sum_x(int *arry)

正常由于arry是含有五个元素的int型数组,所以sizeof(arry)等于20,但由于函数中arry[5]是一个指针,所以在函数中sizeof(arry)等于8

二维数组同理

int two_arry_sum(int arr[3][3]) 等价于 int two_arry_sum_x(int (*arr)[3]) 等价于 int two_arry_sum_x(int (*)[3])

C语言内存管理

可以参考这篇文章,写的非常详细,这里只做总结和补充 

                                              C语言 内存管理 - 知乎 (zhihu.com)

 stdlib.h头文件常用函数介绍
 #include <stdlib.h>---------分配----------void *malloc(size_t size); //分配大小为size 的堆空间 void *calloc(size_t nmemb, size_t size); //分配大写为 size * nmemb 的堆空间 ---------修改----------  void *realloc(void *ptr, size_t size); //修改ptr的堆空间大小为 sizevoid *reallocarray(void *ptr, size_t nmemb, size_t size);//修改ptr的堆空间大小为 size * nmemb---------释放----------  void free(void *ptr); //释放ptr 所指向的堆空间 
1、局部变量
局部变量:自动分配空间,自动释放空间 存储区:栈空间  定义:在函数内部的 花括号定义 { }作用域:只在当前 花括号{ } 内有效 生命周期: 只在当前 花括号{ } 内有效 
 2、全局变量
全局变量: 在整个程序中,都一直存在 存储区:数据段  定义:在所有的函数外面定义  作用域:在整个程序中都有效  生命周期:在整个程序中都有效 
#include <stdio.h>int a = 10, b = 20;void swap_all()
{printf("swap函数中全局变量地址 &a=%p,&b=%p\n", &a, &b);printf("swap函数中全局变量交换前 a=%d,b=%d\n", a, b);int tmp = a;a = b;b = tmp;printf("swap函数中全局变量交换后 a=%d,b=%d\n\n", a, b);
}int main()
{swap_all(&a, &b);printf("main函数中全局变量 a=%d, b=%d\n", a, b);return 0;
}

  输出结果

但是如果在main函数中重新定义 int a,b;则main函数会输出其中的局部变量,因为局部变量在本函数中优先级大于全局变量。

3、 堆空间变量
堆空间变量: 由用户自己去管理空间   (最灵活的内存空间)存储区:堆空间 定义:调用 malloc,calloc 进行分配  作用域:在空间未被释放之前都有效  生命周期:利用 malloc,calloc 分配, 利用 free 释放

int *Heap()
{// int value = 100; //会释放,不能返回int *value = malloc(sizeof(int));// 8个局部变量的指针空间    4个堆空间变量   = 12 个空间*value = 100; // 往堆空间存储数据printf("value=%p,*value=%d\n", value, *value);return value; // 返回堆空间,没问题  , 指针会释放!  堆不会// return &value;
}

 //在堆内存中申请一个空间,依次存入元素

#include <stdio.h>
#include <stdlib.h>void *size1(int size)
{int *p = (int *)malloc(sizeof(int) * size);return p;
}int main()
{int size=5;int *q = size1(size);for(int i = 0; i<5; i++){   q[i] = i;printf("%d\n", q[i]);}}

 内存释放和内存泄露

int *Heap_tmp()
{int *tmp = malloc(sizeof(int));*tmp = 100;printf("tmp=%p,*tmp=%d\n", tmp, *tmp);// 内存泄漏!!堆空间的地址已经找不到了!// 注意:如果在一个函数中使用了堆空间, 记得释放 或者 把空间地址返回出去,否则会出现内存泄漏
}

需要添加free()函数 

4、静态变量
静态变量:在整个程序中,都一直存在存储区:数据段    定义:利用 static 关键字定义  作用域:在整个程序中都有效 生命周期:在整个程序中都有效   

静态局部变量

1.静态局部变量,只能被初始化1次 ,存储在数据段,不会释放。

#include <stdio.h>void increment() {static int count = 0;  // 静态局部变量count++;printf("Count: %d\n", count);
}int main() {increment();  // 第一次调用,count 初始化为 0,然后加 1,输出 1increment();  // 第二次调用,count 不再初始化,直接加 1,输出 2increment();  // 第三次调用,count 继续加 1,输出 3return 0;
}

2.静态全局变量,只能在当前文件使用,无法跨文件使用,防止全局变量名冲突。

5、常量
常量:在整个程序中,都一直存在存储区:数据段  定义:利用 const 关键字定义 作用域:在整个程序中都有效 生命周期:在整个程序中都有效  

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

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

相关文章

Linux文件与相关函数的知识点3

main函数参数 int main(int argc,char *argv[]) { return 0; } C语言规定了main函数的参数只能有两个&#xff0c;一个是argc,一个是argv并且&#xff0c;argc只能是整数&#xff0c;第二个必须是指向字符 串的指针数组。 argc: 参数表示命令行中参数的个数&#xff0…

Java实现七大排序(二)

一.交换排序 1.冒泡排序 这个太经典了&#xff0c;每个学编程都绕不开的。原理跟选择排序差不多&#xff0c;不过冒泡排序是直接交换。 public static void bubbleSort(int[] array){for (int i 0; i < array.length - 1; i) {for (int j 0; j < array.length-1-i; j…

域内攻击手法——AS-REP Roasting攻击和Kerberoasting攻击

一、AS-REP Roasting攻击 1、AS-REP Roasting攻击原理 AS-REP Roasting是一种对用户账户进行离线爆破的攻击方式。但是该攻击方式使用上比较受限&#xff0c;因为其需要用户账户设置不要求Kerberos 预身份验证选项&#xff0c;而该选项默认是没有勾选的。Kerberos 预身份验证…

20240727 每日AI必读资讯

&#x1f310;OpenAI向Google宣战&#xff0c;重磅推出AI搜索引擎SearchGPT &#xff01; - 将 AI 与实时网络信息结合 提供生成式UI结果 - SearchGPT 结合网络最新信息可以直接回答问题&#xff0c;同时注明相关来源链接。 - 还可以像与人对话一样提出后续问题&#xff0c;…

进程概念(三)----- fork 初识

目录 前言1. pid && ppid2. forka. 为什么 fork 要给子进程返回 0&#xff0c; 给父进程返回子进程的 pid &#xff1f;b. 一个函数是如何做到两次的&#xff1f;c. fork 函数在干什么&#xff1f;d. 一个变量怎么做到拥有不同的内容的&#xff1f;e. 拓展&#xff1a;…

小红书电商首提“生活方式电商”定义,个性化需求也能做成好生意

近日&#xff0c;小红书发布COO柯南与经济学者薛兆丰的对谈视频。对谈中柯南首次对外定义&#xff0c;小红书电商是“生活方式电商”。 柯南表示&#xff0c;生活方式电商是让用户在小红书买到的&#xff0c;不仅是好产品&#xff0c;也是一种向往的生活。 随着生活方式的多元…

【初阶数据结构】9.二叉树(4)

文章目录 5.二叉树算法题5.1 单值二叉树5.2 相同的树5.3 另一棵树的子树5.4 二叉树遍历5.5 二叉树的构建及遍历 6.二叉树选择题 5.二叉树算法题 5.1 单值二叉树 点击链接做题 代码&#xff1a; /*** Definition for a binary tree node.* struct TreeNode {* int val;* …

PID 控制实验 - 整定实验

Arduino PID Arduino-PID-LibraryArduino-PID-AutoTune-Library PID控制实验 – 制作测试台 PID Control Experiment – Making the Testing Rig PID (Proportional, Integral, Derivative) control is a classic control algorithm that I have used for a few projects,…

Java面试还看传统八股文?快来看看这个场景题合集吧【附PDF】

以下就是这份面试场景文档↓ 这里有什么&#xff1f; ↓↓ 1.针对 2024 年面试行情的变化设计的面试场景题以及回答思路 2. 如何快速通过面试的详细攻略 3. 简历优化技巧 1.知己知彼才能百战百胜&#xff0c;如何做好面试前的准备工作 场景题答案以及更多场景题八股文一线大…

java学习--枚举

问题引入&#xff1a; 当需要解决一个季节类的问题&#xff0c;我们使用学到的类与对象&#xff0c;创建一个季节的类然后添加构造器在进行分装就可以实现&#xff0c;但问题也随之而来&#xff0c;这样不仅可以有正常的四季还可以添加其他不存在的四季以及可以更改四季的属性…

【Leetcode】十九、贪心算法:玩筹码 + 跳跃游戏

文章目录 1、贪心算法2、leetcode1217&#xff1a;玩筹码3、leetcode55&#xff1a;跳跃游戏 1、贪心算法 关于贪心算法中&#xff0c;“每一步都是最好的选择"的理解”。以零钱兑换为例&#xff0c;现在有1分、2分、5分的硬币&#xff0c;现在要凑出11分&#xff0c;且要…

masscan 端口扫描——(Golang 简单使用总结)

1. 前言 最近要做一个扫描 ip 端口的功能 扫描的工具有很多&#xff0c;但是如何做到短时间扫描大量的 ip 是个相对困难的事情。 市场上比较出名的工具有 masscan和nmap masscan 支持异步扫描&#xff0c;对多线程的利用很好&#xff0c;同时仅仅支持 syn 半开扫描&#xff…

采用先进的人工智能视觉分析技术,能够精确识别和分析,提供科学、精准的数据支持的明厨亮灶开源了。

明厨亮灶视频监控平台是一款功能强大且简单易用的实时算法视频监控系统。它的愿景是最底层打通各大芯片厂商相互间的壁垒&#xff0c;省去繁琐重复的适配流程&#xff0c;实现芯片、算法、应用的全流程组合&#xff0c;从而大大减少企业级应用约95%的开发成本。AI技术可以24小时…

SEO与数据中心代理IP的结合能带来哪些便利?

本文将探讨将SEO与数据中心代理IP结合所带来的好处&#xff0c;以及如何利用这种组合来提升网站在搜索引擎中的排名和可见性。 1. 数据中心代理IP的作用和优势 数据中心代理IP指的是由数据中心提供的IP地址&#xff0c;用于隐藏真实服务器的位置和身份。与其他类型的代理IP相…

【Java基础系列】RBAC:介绍与原理

&#x1f49d;&#x1f49d;&#x1f49d;欢迎来到我的博客&#xff0c;很高兴能够在这里和您见面&#xff01;希望您在这里可以感受到一份轻松愉快的氛围&#xff0c;不仅可以获得有趣的内容和知识&#xff0c;也可以畅所欲言、分享您的想法和见解。 推荐:kwan 的首页,持续学…

【C++】:红黑树的应用 --- 封装map和set

点击跳转至文章&#xff1a;【C】&#xff1a;红黑树深度剖析 — 手撕红黑树&#xff01; 目录 前言一&#xff0c;红黑树的改造1. 红黑树的主体框架2. 对红黑树节点结构的改造3. 红黑树的迭代器3.1 迭代器类3.2 Begin() 和 End() 四&#xff0c;红黑树相关接口的改造4.1 Find…

Java OpenCV 图像处理41 图形图像 图片缩放

Java OpenCV 图像处理41 图形图像 图片缩放 1 图片缩放2 仿射变换3 透视变换 1 图片缩放 Java OpenCV 代码 OpenCV 提供的主要图像缩放函数&#xff0c;可以指定缩放比例或者目标尺寸。 Imgproc.resize(src, dst, new Size(width, height), fx, fy, interpolation);Imgproc.r…

科学又省力 宠物浮毛怎么去掉便捷高效?除毛秘籍养宠空气净化器

上次和朋友逛完街去她家&#xff0c;她家的猫哈基米一开门就飞奔过来&#xff0c;朋友直接抱起它狂亲。结果&#xff0c;猫毛和汗水粘得到处都是&#xff0c;手臂上、脸上都是&#xff0c;看得我这鼻炎星人直起鸡皮疙瘩。很多养宠物的朋友都说&#xff0c;天天给猫狗梳毛&#…

ProcessExplorer免费且功能强大的进程管理软件

ProcessExplorer是一款功能强大的进程管理软件&#xff0c;由Sysinternals开发&#xff0c;并被微软收购。它不仅可以管理和监控系统中的进程&#xff0c;还提供了许多实用的功能&#xff0c;如CPU和内存使用情况的曲线图表、DLL和句柄查看、进程冻结等。 安装ProcessExplorer…

微服务安全——OAuth2.1详解、授权码模式、SpringAuthorizationServer实战、SSO单点登录、Gateway整合OAuth2

文章目录 Spring Authorization Server介绍OAuth2.0协议介绍角色OAuth2.0协议的运行流程应用场景授权模式详解客户端模式密码模式授权码模式简化模式token刷新模式 OAuth 2.1 协议介绍授权码模式PKCE扩展设备授权码模式拓展授权模式 OpenID Connect 1.0协议Spring Authorizatio…