cs61C | lecture4

cs61C | lecture4

C 语言内存布局

### Stack 在最顶部,向下增长。包含局部变量和 function frame information。 > Each stack frame is a contiguous block of memory holding the local variables of a single procedure. > A stack frame includes: > - Location of caller function > - Function arguments > - Space for local variables 栈指针(SP, Stack Pointer) 告诉我们最低(当前)stack frame 在哪里。当进程结束时,SP 会移动回之前的位置,但是数据会保留(现在变成 garbage)。 ```c int main() { a(0); return 1; } void a(int m){ b(1); } void b(int n){ c(2); d(4); } void c(int o){ printf("c"); } void d(int p){ printf("d"); } ``` ![](https://img-blog.csdnimg.cn/img_convert/e5d9b745f8cc324b8aee3336069708c9.png) ![](https://img-blog.csdnimg.cn/img_convert/10f3e24bcc4c8380c5a6da1a90c3e6b4.png) 以下错误代码: ```c int *getPtr(){ int y; y = 3; return &y; } int main(){ int *stackAddr, content; stackAddr = getPtr(); content = *stackAddr; printf("%d", content); /* 3 */ content = *stackAddr; printf("%d", content); /* ? */ } ``` 第一次调用完 getPtr(),getPtr 的栈帧被收回,y 也相应地消失,stackAddr 指向 y 的地址,调用 printf,printf 函数覆盖了原先的栈帧位置,所以再次解引用 stackAddr,不能知道值为多少。 $\textcolor{red}{不要返回指向局部变量的指针!}$ ### Heap 向上增长,可以通过 malloc,realloc 和 calloc 请求空间。可以动态调整大小。 ### Static Data 存储全局和静态变量,这部分不会变化,在整个程序生命周期都一样。 字符串 char* str = "hi" 保存在该区域,**但是字符串数组 char str\[] = "hi" 是保存在栈区!** ### Code 这是程序加载到的位置,也是程序启动的地方。

在函数外定义的变量存储在 Static Data
在函数内部声明的变量存储在 Stack,在函数返回时释放
动态分配的内存存储在 Heap

#include <stdio.h>

int varGlobal; 

int main() {
	int varLocal;
	int *varDyn = malloc(sizeof(int));
}
## Big Endian && Little Endian [字节序 Wiki](https://zh.wikipedia.org/wiki/%E5%AD%97%E8%8A%82%E5%BA%8F) ### Big Endian 大端序:最高位字节存储在最低的内存地址处。 ### Little Endian 最低位字节存储在最低的内存地址处。 ### 常见误区 1.字节序仅适用于那些占有多个字节的值,对于 char c = 97,c == 0b01100001 在大端序和小端序中存储是一样的。 2.寄存器没有任何字节顺序的概念 3.数组和指针的顺序依旧一样。 - int a\[5] = {1, 2, 3, 4, 5} 假设地址为 0x40 - &(a\[0]) == 0x40 && a\[0] == 1 ## 动态内存分配 ### malloc 接受一个参数也就是连续内存块的字节大小,但是它是未初始化的,返回一个指向分配开始的指针。如果分配失败了返回 NULL。 malloc 一般返回 void \*,所以我们要进行类型转换。 ```c int *p = (int *) malloc(n * sizeof(int)); ``` ### free 释放内存,需要传入一个指向分配的块头部的指针。 ### calloc 用于 heap allocation。 他可以将数组中的每个单个条目初始化为 0。 ```c /* void *calloc(size_t nmemb, size_t size); */

int *p = (int *)calloc(5, sizeof(int));

### 常见的内存错误
[What does the "bus error" message mean, and how does it differ from a segmentation fault?](https://stackoverflow.com/questions/212466/what-is-a-bus-error-is-it-different-from-a-segmentation-fault)
#### Segmentation Fault
尝试访问不允许的内存,比如内存访问越界、非法指针使用等。
#### Bus Error
当处理器无法尝试请求的内存访问,例如使用地址不满足对齐要求的处理器指令。
#### 使用未初始化的值
```c
void foo(int *p) {
	int j; /* 未初始化,是 garbage */
	*p = j; 
}

void bar() {
	int i = 10;
	foo(&i);
	printf("i = %d\n", i); /* i 现在包含 garbage */
}
使用不知道的内存
Using Memory You Don’t Own(1)

如果 head 为 NULL,则会引发 Seg Fault

typedef struct node {
	struct node* next;
	int val;
}Node;

int findLastNodeValue(Node* head) {
	/* head 可能为 NULL */
	while(head->next != NULL) {
		head = head->next;
	}
	return ...
}
Using Memory You Don’t Own(2)

以下代码的问题在于该函数返回指向 result 的指针,而 result 是局部变量,在栈区创立,函数返回后该内存空间会被释放。这个指针也就指向了未知的东西。

解决方法:使用动态内存分配,用 malloc 在堆上分配内存,这样即便函数返回,内存也仍然有效。

char *append(const char* s1, const char* s2) { 
	const int MAXSIZE = 128; 
	char* result = (char*)malloc(MAXSIZE * sizeof(char)); // 动态分配内存 
	if (result == NULL) { 
		return NULL; // 检查内存分配是否成功 
	}
	...
Using Memory You Don’t Own(3)

strlen() 函数不会算上结尾的 ‘0’。

同时也要避免双重释放,比如

free(person);
free(person->name);
Using Memory You Haven’t Allocated


实际上这被称为 BUFFER OVERRUN or BUFFER OVERFLOW
安全的版本:

#define ARR_LEN 1024
char buffer[ARR_LEN];

int foo(char *str) {
	strncpy(buffer, str, ARR_LEN);
}
Memory Leaks


pi 是全局变量,所以 foo() 中的 pi 覆盖了 main 函数中,main() 函数内的指针就无法被释放。

创建 Linked List

struct Node {
	char *value; /* 字符串 */
	struct Node *next; /* 指向下一个节点的指针 */
} node;

Adding a Node to the List

s1 -> s2 -> s3 -> NULL

char *s1 = "start", *s2 = "middle", *s3 = "end";
struct node *theList = NULL;
theList = addNode(s3, theList);
theList = addNode(s2, theList);
theList = addNode(s1, theList);

这些字符串实际上存储在静态区。

node *addNode(char *s, node *list) {
	node *new = (node *) malloc(sizeof(NodeStuct));
	new->value = (char *) malloc(strlen(s) + 1); /* '\0' 的存在 */
	strcpy(new->value, s);
	new->next = list;
	return new;
}

Removing a Node from the List

Delete/free the first node
node *deleteNode(node *list) {
	node *temp = list->next;
	free(list->value);
	free(list);
	return temp;
}

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

C语言详解(文件操作)2

Hi~&#xff01;这里是奋斗的小羊&#xff0c;很荣幸您能阅读我的文章&#xff0c;诚请评论指点&#xff0c;欢迎欢迎 ~~ &#x1f4a5;&#x1f4a5;个人主页&#xff1a;奋斗的小羊 &#x1f4a5;&#x1f4a5;所属专栏&#xff1a;C语言 &#x1f680;本系列文章为个人学习…

浅析嵌入式实时系统中信号量的概念

目录 概述 1. 认识信号量 1.1 定义信号量 1.2 信号量的类型 1.2.1 二值信号量 1.2.2 计数信号量 1.2.3 互斥信号量 1.2.3.1 认识互斥信号量 1.2.3.2 互斥信号量的其他特性 2 典型信号量的使用 2.1 等待和信号同步 2.2 多任务等待和信号同步 2.3 信用跟踪同步 2.…

C++ - Clion安装Qt msvc2017版本教程,基础环境配置clion+ Qt5.12.12 msvc2017 + VS2019

背景&#xff1a;平时代码开发使用clion&#xff0c;但使用项目要制定mscv2017版本Qt。先装过mingw版本Qt无法运行&#xff0c;但msvc版本依赖装有Visual Studio&#xff0c;本地装的又是2019版。就出现了这个大坑&#xff0c;需要配置好clion Qt msvc2017 VS2019。 文章目录 …

深度学习中embedding层的理解

Embedding层作用 在深度学习领域中&#xff0c;Embedding层扮演着至关重要的角色&#xff0c;尤其在处理文本数据或类别数据。Embedding层的功能有两个&#xff1a; 1. 将高维稀疏的输入数据&#xff08;如单词、类别标签等&#xff09;转换为低维稠密的向量表示&#xff0c;…

LNMP配置

文章目录 一、相关概念CGI的由来FastCGIPHP-FPM 二、编译安装编译安装nginxyum安装mysql编译安装php配置nginx支持php解析增加数据库安装论坛 一、相关概念 CGI的由来 最早的Web服务器只能简单地响应浏览器发来的HTTP请求&#xff0c;并将存储在服务器上的HTML文件返回给浏览器…

Python | Leetcode Python题解之第144题二叉树的前序遍历

题目&#xff1a; 题解&#xff1a; class Solution:def preorderTraversal(self, root: TreeNode) -> List[int]:res list()if not root:return resp1 rootwhile p1:p2 p1.leftif p2:while p2.right and p2.right ! p1:p2 p2.rightif not p2.right:res.append(p1.val)…

DeepSpeed MoE

MoE概念 模型参数增加很多&#xff1b;计算量没有增加&#xff08;gating小FNN&#xff0c;比以前的大FNN计算量要小&#xff09;&#xff1b;收敛速度变快&#xff1b; 效果&#xff1a;PR-MoE > 普通MoE > DenseTransformer MoE模型&#xff0c;可视为Sparse Model&…

手机投屏到电脑时,手机提示连接失败

前言 注意&#xff0c;本方法建立在你已经通过其他帖子等解决了前置条件的情况下&#xff0c;手机提示连接失败情况下&#xff0c;包括但不限于关闭防火墙、安装无线投屏工具、手机和电脑连接在同一个WiFi频段下、关闭杀毒软件等。 具体操作方法 1、请进入设置 > 系统和…

电脑存储设备,固态硬盘介绍,usb接口

简介 存储设备分为两大类主存和辅存&#xff0c;另外还有专门提供存储服务的网络存储 主存储器 随机存取存储器&#xff08;RAM, Random Access Memory&#xff09; 特点&#xff1a;高速、易失性存储器&#xff0c;断电后数据丢失。用途&#xff1a;临时存储正在使用的数据…

卷积神经网络 convolution neural network

1.数学卷积&#xff1a;滑动窗口 2.图像具有局部相关性和平移不变性&#xff0c;有许多冗余的特征点&#xff0c;如果用全连接的神经网络会很浪费时间。 3.卷积nn&#xff1a;减少参数&#xff0c;滑动提取特征&#xff0c;特征作为下层卷积的输入&#xff0c;然后放到全连接…

Androidstudio项目加载不出来,显示Connect timed out

Android studio加载不出来所需要的环境依赖,99%的问题都是网络原因 解决办法有两个: 1.科学上网 2.使用国内的镜像 方法一自行解决,下面重点介绍方法二 在项目目录下找到gradle->wrapper->gradle-wrapper.properties 将项目的distributionUrl改为https://mirrors.cl…

设计模式-装饰器模式(结构型)

装饰器模式 装饰器模式是一种结构模式&#xff0c;通过装饰器模式可以在不改变原有类结构的情况下向一个新对象添加新功能&#xff0c;是现有类的包装。 图解 角色 抽象组件&#xff1a;定义组件的抽象方法具体组件&#xff1a;实现组件的抽象方法抽象装饰器&#xff1a;实现…

Unity 笔试题分享

1. 请回答以下代码片段执行时是否会产生堆内存分配 a. void SetChar(string s){s.Replace(b, d);}b. void Update(Transform t){t.localPosition new Vector3(0, 0, 0);}c、 int Sum(List<int> l){int total 0;foreach (int i in l){total i;} return total;}d…

C++ | Leetcode C++题解之第144题二叉树的前序遍历

题目&#xff1a; 题解&#xff1a; class Solution { public:vector<int> preorderTraversal(TreeNode *root) {vector<int> res;if (root nullptr) {return res;}TreeNode *p1 root, *p2 nullptr;while (p1 ! nullptr) {p2 p1->left;if (p2 ! nullptr) {…

python教程

python解释器的安装 https://www.python.org/ftp/python/3.12.4/python-3.12.4-amd64.exe jetbrains官网 英文 PyCharm 专业的版本 Thank you for downloading PyCharm! 社区 Thank you for downloading PyCharm! 中文 PyCharm 专业的版本 感谢您下载PyCharm&#xff01…

群体优化算法---水波优化算法介绍以及应用于聚类数据挖掘代码示例

介绍 水波优化算法&#xff08;Water Wave Optimization, WWO&#xff09;是一种新兴的群智能优化算法&#xff0c;灵感来自水波在自然环境中的传播和衰减现象。该算法模拟了水波在水面上传播和碰撞的行为&#xff0c;通过这些行为来寻找问题的最优解。WWO算法由三种主要的操作…

【JavaEE】Spring Boot MyBatis详解(一)

一.MyBatis的基本概念与相关配置. 1.基本概念 MyBatis是一款优秀的持久层框架&#xff0c;用于简化JDBC的开发。MyBatis本是Apache的一个开源项目iBatis&#xff0c;2010年这个项目由apache迁移到了google code&#xff0c;并且改名为MyBatis. 2013年11月迁移到Github.持久层…

区间预测 | Matlab实现GRU-ABKDE门控循环单元自适应带宽核密度估计多变量回归区间预测

区间预测 | Matlab实现GRU-ABKDE门控循环单元自适应带宽核密度估计多变量回归区间预测 目录 区间预测 | Matlab实现GRU-ABKDE门控循环单元自适应带宽核密度估计多变量回归区间预测效果一览基本介绍程序设计参考资料 效果一览 基本介绍 1.Matlab实现GRU-ABKDE门控循环单元自适应…

[Vue3:组件通信)子组件props接收和watch监听,emit发送父组件 (添加修改设置成绩,添加、删除选课记录)

文章目录 一&#xff1a;系统功能&#xff1a;设置成绩&#xff08;添加或修改&#xff09;交互逻辑&#xff1a;涉及页面 Page02.vue&#xff0c;ModalEdit.vue主页面Page.vue注入子页面&#xff0c;使用子页面标签属性主页面对子页面做通信&#xff0c;子页面ModalEdit接收参…

Nginx+Tomcat负载均衡,动静分离群集

Nginx反向代理原理 Nginx 反向代理&#xff1a;将Nginx接收到的请求转发给其它应用服务器处理 Nginx 负载均衡&#xff1a;通过反向代理实现&#xff0c;还可以将nginx接收到的请求转发给多个后端应用服务器处理 Nginx 动静分离&#xff1a;静态页面请求&#xff0c;由nginx…