工程实践实训日报五
项目名称 【苏嵌实训-嵌入式 linux C 第 5天】
今日进度以及任务
今天主要学习了函数命名、形参的设定,内存管理相关的知识点。
本日任务完成情况
跟着老师一起了解了函数的命名、形参的设定,内存管理相关的知识点,对C语言的知识有了一个查漏补缺。
本日开发中出现的问题汇总 malloc和free的实现机制不清楚,能够用数组名直接访问数组的原因不了解。
本日未解决问题 无
本日开发收获 以前只是注重怎么去编程,代码怎么写,不太清楚那些编译系统自定义的库函数究竟是怎样实现的,通过今天的课程,我对malloc和free的实现机制有了一个基本的了解,除此之外,对于“为什么能用数组名直接访问数组?”这个已经很习惯使用了,但是为什么成立却不知所以然的问题,现在也理解了,数组名相当于一个常量指针,存储的是数组的首地址。
其他 今天还是有很多收获的,期待每一天都能遇见一个更好的自己。
作业
1.free是如何知道释放多大的空间?(malloc实现原理?)
分配内存的时候会在内存块的地址前面的4个字节处存放内存块的大小,使用free函数释放内存的时候,从这个位置就可以找到内存块的大小。
malloc基本的实现原理就是维护一个内存空闲链表,当申请内存空间时,搜索内存空闲链表,找到适配的空闲内存空间,然后将空间分割成两个内存块,一个变成分配块,一个变成新的空闲块。
2.static在什么时候使用?
若全局变量仅在单个C文件中访问,则可以将这个变量修改为静态全局变量,以降低模块间 的耦合度;若全局变量仅由单个函数访问,则可以将这个变量改为该函数的静态局部变量,以降 低模块间的耦合度;设计和使用访问动态全局变量、静态全局变量、静态局部变量的函数时,需要考虑重入问题。
3.为什么要使用typedef给类型重命名?
类型重命名是给一个已有的数据类型声明一个新名字,新名字是数据类型的别名。类型重命名,可以为现有类型创建别名,定义易于记忆的类型名,便于简化代码和批量修改具体类型。
笔记
1. 输入一个字符串,同时输入帧头和帧尾(可以是多个字符),将该字符串中合法的帧识别出来。
#include <stdio.h>
#include <string.h>
int main()
{
char str[100];
char str1[100];
char str2[100];
printf("Input a string:\n");
gets(str);
printf("Input the head:\n");
gets(str1);
printf("Input the tail:\n");
gets(str2);
char *p = str;
char *p1 = str1;
char *p2 = str2;
char *p3 = NULL;
char *p4 = NULL;
printf("Legal sub-string:\n");
while(*p)
{
if(strncmp(p, p1, strlen(str1)) == 0) //比较头
{
p3 = p;
while(*p3)
{
if(strncmp(p3, p2, strlen(str2)) == 0) //比较尾
{
int j = p3 - p + strlen(str2);
int i;
p4 = p;
for(i = 0; i < j; i++)
{
printf("%c", *p4++);
}
puts("\0");
}
*p3++;
}
}
*p++;
}
return 0;
}
2. 函数
-
函数的三要素
函数名:命名具有自注释性,一般“v.+n.”形式,如:add_user
参数:实参是什么类型,形参就要定义成什么类型
数组名就是一个指针常量,它代表数组元素在内存中的首地址。
注:数组名是一个指针,但是说它是常量的意思是它本身不可更改:如定义int a[34][3],a确实是个指针,*a指向数组中第一个整数;但是不能通过a++操作使在此操作后a指向数组中第二个整数,而普通指针(int a[12];int *b=a;b 就是普通指针)可以这么操作,所以说它是“指针常量”。
//验证程序: #include "stdio.h" void main() { int a[3]={0,1,2}; printf("%d\n",a); printf("%d\n",&a[0]); } //程序第一行输出的就是数组a的首地址 //第二行输出的是a[0]的地址 //但是两个值是一样的。
注:传数组名:
传一维数组名,用元素的指针;
传二维数组名,用一维数组指针;
传三维数组名,用二维数组指针;
传指针数组名,用指针的指针;
传地址和传值:什么时候传地址,什么时候传值?
当只使用不修改实参变量对应空间的值时,传实参变量名; 当既使用也修改实参变量对应空间的值时,传实参变量对应空间的地址。
返回值
return、exit(异常结束)
-
函数指针
函数指针变量:保存函数的入口地址
函数名作用:指针常量,保存函数入口地址(函数地址)
函数指针的作用:做函数形参,实现回调函数(多态、代码扩展性)
-
练习:编写一个函数,将句子中的单词位置倒置,而不改变单词内部结构。
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#define SIZE 255
void reorder (char *s)
{
char *p1 = s;
char *p2;
int i = 0;
int count = 0;
while( (*p1) != '\0')
{
p1++;
count++;
}
p1--;
while(count > 0)
{
while( (*p1) != ' ' && count > 0)
{
p1--;
i++;
count--;
}
p2 = p1+1;
while( i > 0)
{
putchar(*p2);
p2++;
i--;
}
if( (*p1) == ' ')
{
putchar(*p1);
p1--;
count --;
}
}
}
int main ()
{
char str[SIZE];
printf("Input a string:\n");
gets(str);
printf("Result:\n");
reorder(str);
printf("\n");
return 0;
}
3. 内存管理
- 内存是稀缺资源
- 低地址------------------------------>高地址
代码段 数据段 堆空间 栈空间 内核
3.内存池
malloc/free是个开销非常大的操作;
malloc申请的内存后期需要使用free函数进行回收,以避免内存 泄漏。
-
关键字
register:寄存器变量,尽可能的将数据保存到CPU的寄存器中(频繁使用的变量适用)
static:修饰局部变量,延长了变量生命周期,程序结束才释放; 修饰全局变量,静态全局变量,该变量在其他文件无法访问;修饰函数,该函数只能被本文件函数调用,不可被其他文件访问
(static在什么时候使用?)
若全局变量仅在单个C文件中访问,则可以将这个变量修改为静态全局变量,以降低模块间 的耦合度;若全局变量仅由单个函数访问,则可以将这个变量改为该函数的静态局部变量,以降低模块间的耦合度;设计和使用访问动态全局变量、静态全局变量、静态局部变量的函数时,需要考虑重入问题。 extern:外部声明,告诉编译器这个函数或变量是在其他文件定义的.
const:修饰变量,该变量成为一个只读变量(值是可以通过指针修改,不可通过变量名修改)
注:修饰某个变量时,一定要初始化
就近原则 typedef:(为什么要使用typedef给类型重命名?)
类型重命名是给一个已有的数据类型声明一个新名字,新名字是数据类型的别名。类型重命名,可以为现有类型创建别名,定义易于记忆的类型名,便于简化代码和批量修改具体类型。