深度解析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://xiahunao.cn/news/3268356.html

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

相关文章

鸿蒙APP架构及开发入门

1.鸿蒙系统 1.1 什么是鸿蒙 鸿蒙是一款面向万物互联时代的、全新的分布式操作系统。 在传统的单设备系统能力基础上&#xff0c;鸿蒙提出了基于同一套系统能力、适配多种终端形态的分布式理念&#xff0c;能够支持手机、平板、智能穿戴、智慧屏、车机、PC、智能音箱、耳机、…

《程序猿入职必会(4) · Vue 完成 CURD 案例 》

&#x1f4e2; 大家好&#xff0c;我是 【战神刘玉栋】&#xff0c;有10多年的研发经验&#xff0c;致力于前后端技术栈的知识沉淀和传播。 &#x1f497; &#x1f33b; CSDN入驻不久&#xff0c;希望大家多多支持&#xff0c;后续会继续提升文章质量&#xff0c;绝不滥竽充数…

lua 游戏架构 之 游戏 AI (九)ai_mgr Ai管理

定义ai_mgr的类&#xff0c;用于管理游戏中实体的AI组件。 先定义 AI行为枚举和优先级&#xff1a; lua 游戏架构 之 游戏 AI &#xff08;八&#xff09;ai_tbl 行为和优先级-CSDN博客https://blog.csdn.net/heyuchang666/article/details/140712839?spm1001.2014.3001.55…

天工三维实景建软件 GodWork 3D 7.24 软件下载License使用

1、天工三维实景建软件GodWork 3D 7.24,城市级实景三维数据生产面临大数据量空三稳定解算的难题。受限于目前主流软件的解算能力与效率&#xff0c;生产单位常采用分块处理方法&#xff0c;接边处精度需要有足够的控制点来保证&#xff0c;这增加了外业布设控制点与内业的工作量…

巴斯勒相机(Basler) ACE2 dart 系列说明和软件

巴斯勒相机(Basler) ACE2 dart 系列说明和软件

开始尝试从0写一个项目--后端(三)

器材管理 和员工管理基本一致&#xff0c;就不赘述&#xff0c;展示代码为主 新增器材 表设计&#xff1a; 字段名 数据类型 说明 备注 id bigint 主键 自增 name varchar(32) 器材名字 img varchar(255) 图片 number BIGINT 器材数量 comment VARC…

Redis底层数据结构的实现

文章目录 1、Redis数据结构1.1 动态字符串1.2 intset1.3 Dict1.4 ZipList1.5 ZipList的连锁更新问题1.6 QuickList1.7 SkipList1.8 RedisObject 2、五种数据类型2.1 String2.2 List2.3 Set2.4 ZSET2.5 Hash 1、Redis数据结构 1.1 动态字符串 Redis中保存的Key是字符串&#xf…

php收银系统源码-收银员操作权限

收银系统是很多门店&#xff0c;尤其是连锁门店营业的必备工具&#xff0c;收银员每天需要通过收银系统记录商品的售卖数量&#xff0c;以及收款&#xff0c;会员开卡&#xff0c;核销订单等工作。但很多门店都不希望给收银员太高的权限&#xff0c;自然就离不开收银员的权限管…

windows server服务器/linux服务器离线安装pandas

windows server服务器/linux服务器离线安装pandas pypi官网下载whl文件速度较慢&#xff0c;推荐使用国内的镜像源来下载&#xff0c;镜像源地址为 清华大学 &#xff1a;https://pypi.tuna.tsinghua.edu.cn/simple/ 阿里云&#xff1a;http://mirrors.aliyun.com/pypi/simple…

Python | Leetcode Python题解之第278题第一个错误的版本

题目&#xff1a; 题解&#xff1a; # The isBadVersion API is already defined for you. # def isBadVersion(version: int) -> bool:class Solution:def firstBadVersion(self, n: int) -> int:left, right 1, nwhile left < right:mid left (right - left) //…

Dockerfile指令详解和Docker操作命令

1.容器的特点&#xff1a;1&#xff09;自包含&#xff08;包括应用程序及其运行环境&#xff09;&#xff1b;2&#xff09;可移植&#xff1b;3&#xff09;相互隔离&#xff1b;4&#xff09;轻量级。 2.docker成为容器的事实标准在于&#xff1a;1&#xff09;在运行环境上…

【通信模块】LoraWAN网络简介

LoRaWAN网络 技象科技相关文章总结&#xff0c;学习笔记&#xff0c;原文链接如下&#xff0c;转载请标明该出处&#xff1a; LORA&#xff1a; https://www.techphant.cn/tag/l-2 LORAWAN&#xff1a;https://www.techphant.cn/tag/l-3 其他&#xff1a;如LAN https://www…

静止轨道卫星大气校正(Atmospheric Correction)和BRDF校正

文章内容仅用于自己知识学习和分享&#xff0c;如有侵权&#xff0c;还请联系并删除 &#xff1a;&#xff09; 目的&#xff1a; TOA reflectance 转为 surface refletance。 主要包含两步&#xff1a; 1&#xff09;大气校正&#xff1b; 2&#xff09;BRDF校正 进度&#x…

repo 工具安装和使用教程(windows+gitee)

repo是什么 官方的定义&#xff1a;Repo是谷歌用python脚本写的调用git的一个脚本&#xff0c;可以实现管理多个git库。 Android的源代码使用Repo 命令行工具来管理多个git仓库&#xff0c;大概有百多个。要想克隆和管理百多个 Git 仓库&#xff0c;不是一件简单的事情。Repo 命…

嵌入式Python、ROS、SLAM、WebSocket和Node.js:智能巡逻监控安防机器人设计流程(代码示例)

项目概述 随着智能技术的发展&#xff0c;智能巡逻机器人在安防、监控和巡逻等领域的应用越来越广泛。本文将介绍一个结合嵌入式系统、机器人技术和后端开发的智能巡逻机器人。该机器人能够自主导航&#xff0c;实时检测异常情况&#xff08;如火灾或入侵者&#xff09;&#…

H616布线--规则设置于NET分组

一定先看工艺能力&#xff0c;再设计&#xff1a; 嘉立创盘中孔&#xff08;树脂塞孔电镀盖帽&#xff09;设计指引及规则 https://www.jlc.com/portal/q7i38630.html https://www.jlc.com/portal/vtechnology.html 这是我们的工艺参数&#xff0c;请您参考一下呢&#xff01…

Java_如何在IDEA中使用Git

注意&#xff1a;进行操作前首先要确保已经下载git&#xff0c;在IDEA中可以下载git&#xff0c;但是速度很慢&#xff0c;可以挂梯子下载。 导入git仓库代码 第一次导入&#xff1a; 首先得到要加载的git仓库的url&#xff1a; 在git仓库中点击 “克隆/下载” 按钮&#xf…

牛客TOP101:寻找峰值

文章目录 1. 题目描述2. 解题思路3. 代码实现 1. 题目描述 2. 解题思路 使用双指针&#xff0c;我们只需要找到一个峰值就可以了。 这个很重要&#xff0c;要记住。   我们先取到数组中间的值&#xff0c;让它与它的前一个或者后一个进行比较&#xff08;下面的代码实现是与后…

1、hadoop环境搭建

1、环境配置 ip(/etc/sysconfig/network-scripts) # 网卡1 DEVICEeht0 TYPEEthernet ONBOOTyes NM_CONTROLLEDyes BOOTPROTOstatic IPADDR192.168.59.11 GATEWAY192.168.59.1 NETMASK 255.255.255.0 # 网卡2 DEVICEeht0 TYPEEthernet ONBOOTyes NM_CONTROLLEDyes BOOTPROTOdh…

kafka源码阅读-ReplicaStateMachine(副本状态机)解析

概述 Kafka源码包含多个模块&#xff0c;每个模块负责不同的功能。以下是一些核心模块及其功能的概述&#xff1a; 服务端源码 &#xff1a;实现Kafka Broker的核心功能&#xff0c;包括日志存储、控制器、协调器、元数据管理及状态机管理、延迟机制、消费者组管理、高并发网络…