irpas技术客

刨析《C语言》【进阶】付费知识【完结】_Choice~

大大的周 1478

文章目录 动态内存开辟mallocreallocreturn 数据的存储大端和小端整形提升 文件标准错误编译文件过程 预编译define与typedef的取别 针对无具体类型的操作内存变量的生命周期static静态存储和动态变量的异同**:存储方式静态存储和动态变量的异同**:存储方式

动态内存开辟 malloc

只是从内存池中提取一块合适的内存,并不会初始化,如果需要初始化,要么手动,要么使用calloc函数

动态开辟的空间,2种收回方式

主动释放程序结束 对NULL指针的解引用 if(p==NULL) { printf("错误"); return ; }对动态开辟空间的内存越界访问使用free释放非动态开辟的空间使用free释放动态的内存中的一部分对同一块动态开辟的空间,多次释放动态开辟的空间忘记释放,会造成内存泄露手动把p置成空 p=NULL;

Void GetMemory2(char **p, int num) { *p = (char *)malloc(num); } void Test(void) { char *str = NULL; GetMemory(&str, 100); strcpy(str, "hello"); printf(str); }还差 free(str); str=NULL; void Test(void) { char *str = (char *) malloc(100); strcpy(str, “hello”); free(str); if(str != NULL) { strcpy(str, “world”); printf(str); } }//内存访问错误,因为free了,虽没有消失,但找不到内存地址了,没有访问权限;还是会进入if,因为没有手动置空

以上例题来源于《高质量的C/C++编程》

realloc

增容函数:把原先那块内存的内容复制到新块上,因此,不能再使用指向旧内存的指针,而是使用realloc所返回的新指针

return

在函数return 只能返回堆上的内存 比如malloc申请的堆内存,而char p[]="hello world"; return p;//err 例:

int *p(void) { int x= 10; return (&x); } 数据的存储 大端和小端

整形提升 #include<stdio.h> int main() { //unsigned char 0-255 unsigned char a =200; //00000000000000000000000011001000 -char类型占一个字节就是8位 //11001000 unsigned char b =100; //00000000000000000000000001100100 //01100100 unsigned char c=0 ; //a和b整形提示 //00000000000000000000000011001000 //00000000000000000000000001100100 //00000000000000000000000100101100 c = a + b;//整形先提升再相加 会截断 //00101100 //00000000000000000000000000101100 // printf("%d %d ",a+b, c); // 300 44 return 0; } 文件

**#include<文件名>**到系统提供的指定路径下,找文件,如果找不到,就报错 **#include"文件名"**先到当前路径找下文件,找不到就执行#include<文件名>的过程,如果还找不到,就报错 如果找到文件后,就将文件的内容复制粘贴带#include预处理指令出现的位置

系统指定路径在:

gcc -E test.c -o test.i -v

#include “…” 搜索从这里开始: #include <…> 搜索从这里开始:

/usr/lib/gcc/x86_64-redhat-linux/4.8.5/include /usr/local/include /usr/include

搜索列表结束。 蓝色部分就是系统指定路径,可cd /usr/include查看

标准错误

0:标准输入 1:标准输出 2:标准错误输出 “>”表示重定向,&2表示标准错误输出的通道,所以1>2&表示标准输出重定向到标准错误输出通道; 而1>2表示标准输出重定向到文件名为2的文件中。

编译文件过程

1.预处理:对源文件进行预处理生成预处理文件,预处理CPP根据预处理指令(如#include,#define等)所包含的文件内容插入程序中

gcc -E test.c -o test.i//可查看编译过程,用vim test.i 。最后面有详细过程 printf("ARE=%.2f\n",ARE(3+2));==> printf("ARE=%.2f\n",3.14 *(3+2)*(3+2));

2.编译:根据预处理文件,编译为汇编语言,调用汇编程序生成汇编代码(.s文件)

gcc -S test.s -o test.o

3.汇编:调用汇编程序,翻译成机器语言,生成目标文件(.o文件)

gcc -c test.s -o test.o

4.链接:将test.o和运行时文件,库函数进行链接,调用连接器,将程序中用到的函数加到程序中,生成可执行文件

gcc test.o -o test 预编译

注释一般用#if 0…else …#endif 用来保存到预处理文件中

预编译又叫预处理。预编译不是编译,而是编译前的处理。这个操作是在正式编译之前由系统自动完成的**。预编译又叫预处理。预编译不是编译,而是编译前的处理。这个操作是在正式编译之前由系统自动完成的。

#define 定义一个预处理宏 #undef 取消宏的定义 #if 编译预处理中的条件命令,相当于C语法中的if语句 #ifdef 判断某个宏是否被定义,若已定义,执行随后的语句 #ifndef 与#ifdef相反,判断某个宏是否未被定义 #elif 若#if, #ifdef, #ifndef或前面的#elif条件不满足,则执行#elif之后的语句,相当于C语法中的else-if #else #if, #ifdef, #ifndef对应, 若这些条件不满足,则执行#else之后的语句,相当于C语法中的else #endif #if, #ifdef, #ifndef这些条件命令的结束标志. defined  与#if, #elif配合使用,判断某个宏是否被定义

define与typedef的取别

你应该使用typedef而不是#define来创建新的类型,因为后者无法正确地处理指针类型

#define pro_char char * pro_char a,b; //正确声明了a,但是b却被声明了一个字符 针对无具体类型的操作

无具体类型不能对它解引用

内存

变量的生命周期

变量的生命周期就是从变量地址空间的分配到变量地址空间的释放 程序是静态存储在磁盘上的文件,程序是指令的集合,程序不运行,就谈不上变量地址空间的分配。 程序运行过程对计算机资源的使用的描述就是进程。同一个进程每一次运行就是一个进程。当我们在命令行键入./ 可执行文件的时候,程序就开始运行了。 程序的运行分为两个阶段,分别是加载和执行。程序首先被加载到具体的地址空间,比如全局变量、静态局部变量和函数…,我们将其称为程序的符号。程序符号的具体地址,在加载阶段就已经分配好了。我们称这样的存储区为静态存储区。 程序加载完毕,找到main函数,然后开始执行程序,在程序执行阶段,遇到定义自动局部变量的语句的时候,系统自动为这些自动局部变量分配空间,局部变量才诞生了。这些局部变量所在的区域称为**动态存储区。**这些变量的地址是系统自动分配的,当所在函数的复合语句结束的时候,自动释放其地址空间。所以称为静态分配。还有一种,在程序执行的过程中,程序需要的地址空间的大小不确定,需要程序员根据实际情况,向系统提出申请,这样的分配的地址空间称为动态分配。 程序执行的时候,需要将可执行程序加载到内存中,CPU从内存中读取程序的指令

数据类型:首先由变量的名字找到变量的地址,然后根据变量的类型访问地址空间里的内容

static

修饰局部变量:局部变量的生命周期变长 修饰全局变量:改变了变量的作用域,让静态的全局变量只能在自己所在的源文件内部使用,出了源文件就没法再使用了。 修饰函数:改变了函数的链接属性 外部链接属性->内部链接属性

#include<stdio.h> void cout(void){ int i =0; printf("cout i++=%d\n",i++); return ; } //静态变量在编译值赋一次初值,而自动变量赋初值是在函数调用时,每调用一次就要重新赋初值 void cout_c(void){ static int i =0;//静态局部变量 printf("cout i++=%d\n",i++); return ; } int main() { int i; for(i=0;i<5;i++) cout(); for(i=0;i<5;i++) cout_c(); return 0; } /* 运行结果: cout i++=0 cout i++=0 cout i++=0 cout i++=0 cout i++=0 cout i++=0 cout i++=1 cout i++=2 cout i++=3 cout i++=4

在count函数里,变量i是自动局部变量,调用到函数count的时候,才为其分配地址空间, 并将初值设置为0,然后输出的值,再将i的值自增,然后,函数调用完毕,变量i的地址空间也就到站了, 所以再次调用的时候,再为其分配,…。 所以一直输出是0。countc函数里的静态局部变量,在程序加载的时候,程序执行之前就已经确定了其地址空间, 并将其初始值设置为0,调用这个函数的时候,先输出i的值为0,然后再将i自增,i的值就变为1,函数调用完毕, 函数内的自动局部变量的地址空间释放,但是静态局部变量的地址空间并没有释放所以再次调用的时候i的值为1,然后自增…。 直到整个程序运行完毕的时候,才释放静态局部变量i的值。

静态存储和动态变量的异同**:

相同:都需要分配内存 不同:静态变量是由系统自动分配,释放,程序员无法在程序运行过程手动分配,也无法在程序运的过程中手动释放,静态变量是在栈中分配的 动态变量是由程序员手动分配,释放,程序员可以在程序运行过程手动分配,也可以在程序运的过程中手动释放,可以在函数地执行过程中的任何一个时刻手动释放动态变量的空间,不需要等函数终止时候释放,静态变量是在堆中分配的(链表)

程序的运行分为两个步骤: 1.加载,将程序从硬盘加载到地址空间 2.执行,找到main函数开始执行

在程序执行之前,就已经分配了地址空间的变量或常量,存放在静态存储器 程序运行期间一直存在 在 程序执行期间,执行那条语句的时候再为变量分配地址空间,存放在动态存储区,系统自动管理 satic声明之后为内部,只在源文件中使用,也不允许调用内部函数 extern扩展变量的作用域

存储方式

为其分配,…。

所以一直输出是0。countc函数里的静态局部变量,在程序加载的时候,程序执行之前就已经确定了其地址空间, 并将其初始值设置为0,调用这个函数的时候,先输出i的值为0,然后再将i自增,i的值就变为1,函数调用完毕, 函数内的自动局部变量的地址空间释放,但是静态局部变量的地址空间并没有释放所以再次调用的时候i的值为1,然后自增…。 直到整个程序运行完毕的时候,才释放静态局部变量i的值。

静态存储和动态变量的异同**:

相同:都需要分配内存 不同:静态变量是由系统自动分配,释放,程序员无法在程序运行过程手动分配,也无法在程序运的过程中手动释放,静态变量是在栈中分配的 动态变量是由程序员手动分配,释放,程序员可以在程序运行过程手动分配,也可以在程序运的过程中手动释放,可以在函数地执行过程中的任何一个时刻手动释放动态变量的空间,不需要等函数终止时候释放,静态变量是在堆中分配的(链表)

程序的运行分为两个步骤: 1.加载,将程序从硬盘加载到地址空间 2.执行,找到main函数开始执行

在程序执行之前,就已经分配了地址空间的变量或常量,存放在静态存储器 程序运行期间一直存在 在 程序执行期间,执行那条语句的时候再为变量分配地址空间,存放在动态存储区,系统自动管理 satic声明之后为内部,只在源文件中使用,也不允许调用内部函数 extern扩展变量的作用域

存储方式


1.本站遵循行业规范,任何转载的稿件都会明确标注作者和来源;2.本站的原创文章,会注明原创字样,如未注明都非原创,如有侵权请联系删除!;3.作者投稿可能会经我们编辑修改或补充;4.本站不提供任何储存功能只提供收集或者投稿人的网盘链接。

标签: #刨析C语言进阶付费知识完结 #只能返回堆上的内存