锐单电子商城 , 一站式电子元器件采购平台!
  • 电话:400-990-0325

C语言高级部分总结

时间:2022-10-06 22:00:01 球阵式集成电路

一、内存大话题
1.内存是程序的立足点,体现了内存的重要性。
1.1.内存理解:内存物理有很多Bank(即行列阵式的存储芯片),每个Bank列是位宽 ,每一行就是Words,存储单元的数量=行数(words)×列数(位宽)×Bank一般也用M×W表示芯片容量(或芯片规格/组织结构)。
M以位宽为单位的总容量为兆 ,W代表位宽, 单位是bit。计算出的芯片容量也是基于bit作为单位,用户可以用除以8的方法转换为字节(Byte)。比如8M×8,这是一个8bit有8个位宽芯片M总容量为64的存储单元Mbit(8MB)。
1.2、c没有语言bool类型:以0表示假,非0表示真,则存储在内存中int类型存储。如果你想表示真假,你可以使用它int/char替换型,在c 中就有bool x=true/false;
1.3.内存对齐:内存对齐(提高访问效率)
1.4、char/int/short/long/float/double类型:内存的长度和分析。(int *)0,使0地址指向一个int类型。例如,0000110101010101可以分析成int类型也可以分析成float型。

1.5、Linux核心是面向对象的,而c语言是面向过程的,但可以用结构内嵌指针成为面向对象。

struct student

{

int age; //变量
int lenth; //将相当于一个类,有变量和函数
char *name;
void (*eat)(void); //函数指针

}

1.6.对栈的理解:

(1) 运行时自动分配&自动回收:堆栈是自动管理的,程序员不需要手动干预。方便和简单。(当代码汇编时,它将自动编译成汇编码,以实现函数调用后立即更改屋顶)

(2) 重复使用:堆栈内存实际上是程序中的空间,程序重复使用这个空间。(硬件上有一个用于存储堆栈顶部地址的寄存器,堆栈有大小空间)
(3) 脏内存:由于堆栈内存的重复使用,程序不会在每次使用后清理,因此原始值将在分配时保留。
(4) 临时性:(函数不能返回栈变量指针,因为这个空间是临时的)
(5) 栈会溢出:因为操作系统提前给出了栈的大小,如果栈内存在函数中无穷无尽的分配总能用完。栈的操作(如何离开栈,如何进入栈)是由具体硬件干预的,程序员只需要了解原理。 但要给相应的栈寄存器赋值。调用函数时,变量会自动放入栈中(入栈)。函数调用后,栈会自动离开栈.
( 6 ) 栈的 "发展"有四种情况,满增栈、满减栈、空增栈、空减栈。至于那种要根据编译器来决定,s5pv210 是满减栈。

1.理解7、堆:

(1)操作系统堆管理器管理:堆管理器是操作系统的模块,堆管理内存分配灵活,按需分配。

(2)大块内存:堆内存管理者总量大的操作系统内存块,可按需申请使用,使用后释放。
(3)脏内存:堆内存也是重复使用的,用户在释放前不会清除,所以也很脏。
(4)临时性:堆内存只在malloc和free它属于我的过程,可以访问。malloc之前和free之后不能再访问,否则会有不可预测的后果。
(5)手动申请程序&释放:手工是指需要编写代码申请malloc和释放free。(记住:不要丢失申请地址, 否则不能用,也不能释放)
申请一段内存可以是: malloc(10*sizeof ( int ) ); 原型:void *malloc(size_t size); //指针函数 size_t是宏定义int 便于移植 ,返回内存地址,void *可以看出,强制性类型的内存用于存储所需的内存。 calloc( 10,sizeof ( int ) ); 原型:void *calloc(size_t nmemb, size_t size);// nmemb每个单元,每个单元size字节
void *realloc(void *ptr, size_t size);// 改变原申请空间的大小ptr原来申请内存的指针,size想重新申请内存的大小
使用就是*(p 1)=12 ; *(P 3)=110;
申请失败返回NULL,申请成功返回地址后,必须进行检查(NULL!=p)用完一定要 free ( p ) ;释放后不能使用,也不应使用。可以给它洗盘子,p=NULL; 事实上,申请的内存并不能真正改变大小。原则是先重新申请一段内存,然后将原始内存复制到新内存中,然后释放原始内存,返回新指针。
(6) 在申请内存时,malloc(0)其实是成功的,因为系统规定的尺寸少于一定数量,所以都申请规定的尺寸,比如win在32系统下申请不到32字节的地址,最终申请的空间是32字节。

1.8.内存中的数据:

(1)代码段:存储代码二进制,常量(char *p="linux",则”linux存储在代码段中是不可改变的)

(2) 数据段: 存储非0全局变量和静态局部变量(局部只属于函数,而不是整个程序)
(3) bss : 存储为0的全局变量/静态局部变量为0,存储未初始化的全局变量/静态局部变量
注意:const int a=9; 有两种存储方式:第一种是存储在代码段中,这样a就不能修改,第二种是仍然存储在数据段中,让编译器判断,如果有更改的代码会报告错误。 至于那种,是不确定的,就像单片机属于第一种一样。

1.9.1一个源文件实际上是以段为单位编译成可执行文件的(a .out );可执行文件一般分为数据段、代码段、自定义段和数据段 .bbs 段落。执行时会删除杂段。a.out分为杂段,数据段(存储非0全局变量).bbs段,代码段。
2内存实际上分为两个区域,一个是系统区域,另一个是用户区域,每个区域分为几个小区域,包括堆叠、堆栈和代码区域,.bbs数据区(存储非0全局变量)。
对于有操作系统来说, 当我们执行时a.out在执行文件时,执行文件的程序将帮助我们清除杂项,然后将相应的段加载到内存对应的段。对于裸机程序,我们将使用一套工具a.elf可执行程序清除了所有段的符号信息纯二进制.bin格式烧录文件。因此,加载到内存的程序是连续的,即代码段和数据段,.bbs段都是连续的。当然,栈空间是我们自己设置的。我们不能在裸机中使用它malloc函数,因为我们只使用编译器和连接器工具,没有集成库函数,也没有定义堆空间区。
多程序程序运行情况: 在Linux系统中运行cdw1.out运行此文件的程序将帮助我们将相应的段加载到内存对应的段。然后操作系统将下载到内存的具体物理地址和每个命令(32位)的链接地址映射到TTB当我们再次运行时(一段内存空间)cdw2.out时间,也一样cdw1.out同样加载并映射TTB表中。而且这两个.out文件默认都是链接0地址(逻辑),当cpu发出虚拟地址(Linux中程序逻辑地址)TTB物理地址不同。所以对于每个程序程序的4G其他程序看不到内存空间。

二、位操作
2.1 ~(0u)是全1;
2.2 位与& 位或 | 位取反~ 位异或^
2.三、位与、位或、位异或特征总结:
位与:(任何数字实际上都是1或0)与1位和无变化,与0位和变成0
或:(任何数字实际上是1或0)与1或1,与0或无变化
位异或:(任何数字实际上是1或0)与1位异或会反转,与0位异或无变化

2.4、左移位<< 与右移位>> C语言移位取决于数据类型。
对于无符号数,左移时右侧补0(相当于逻辑移位)
对于无符号数,右移时左侧补0(相当于逻辑移位)
&nsp;               对于有符号数,左移时右侧补0(叫算术移位,相当于逻辑移位)
                                                  对于有符号数,右移时左侧补符号位(如果正数就补0,负数就补1,叫算术移位)
 
2.5、小记:常与  1 拿来 做位运算。让他取反、移位 得到想要的数。

2.6、直接用宏来置位、复位(最右边为第1位)。 置位置1,复位置0  ;
          #define SET_NTH_BIT(x, n)  (x | ((1U)<<(n-1)))
          #define CLEAR_NTH_BIT(x, n) (x & ~((1U)<<(n-1)))

三、指针—精髓 
3.1  printf("%p n"); 其中%p表示输出一个指针,就是指针变量(其存放的那个地址),可以理解为输出一个地址。

3.2  int* p1, p2 ;     等同于 int *p1;   int  p2;  int *p="Linux",其不能改变*P,因为”linux"是一个常数。

3.3 ( 代码规范性 )在定义指针时,同时赋值为NULL,在用指针时,先判断它是不是NULL。尤其是在malloc申请内存后,free(p);则一定要让p=NULL

3.4  C/C++中对NULL的理解: #ifdef _cplusplus// 定义这个符号就表示当前是C++环境
                                                       #define NULL 0;// 在C++中NULL就是0
                                                       #else
                                                       #define NULL (void *) 0;// 在C中NULL是强制类型转换为void *的0
                                                       #endif
3.5、修饰词:const (修饰变量为常量,应该理解为不应该去变它,当作常量,而并非永远不能改变,当然要看具体运行环境,在gcc,const 这种就可以采用指针方式修改,但是
在VC6.6++中就不可以修改):其虽然是当作常数,但是仍然存放在数据段中,用指针仍然可以改变值。
第一种:const int *p;   
第二种:int const *p;
第三种:int * const p;
第四种:const int * const p;
3.6、 数组 int a[2]; 其中a是指首元素的首地址,&a是整个数组的收地址(数组指针,其这个指针指向一个数组),他们的值是一样的,但意义不一样,可以参照 int a; int *p=&a; 来理解。数组和指针天生姻缘在于数组名;int a[3]; int* p=a;是可以的,但是 int *p=&a;就会报错,尽管他们的值是一样的,但意义不一样,所以是不允许的,除非强制类型转换。在访问时是a[0],其实编译器会把它变成*(a+0)的方式,只是用a[0]看起来更方便,封装了一下而已,实质还是指针。

3.7、 siziof()是一个运算符,测试所占内存空间,如 int a[100] ;sizeof(a)=400; 与strlen( )要有所区别,他是测字符串实际长度的,不包括‘‘,如果给strlen传的参数不是一个字符串,则它会一直去找,直到 找到第一个 ‘’,然后再计算其长度。如 char a[]="chen"; char *p=a; 则strlen(p)=4; 
 
3.8、 当数组作为一个形参时,其实参是一个数组名(也可以是指针,其本质就是指针),意义是首元素的首地址,则传过去只影响形参的第一个元素。形参数组的地址被实参数组地址所绑定;实参的大小会丢失,所以往往会传一个int num 大小进去。
 
3.9、 结构体做为形参时,应尽量用指针/地址方式来传,因为结构体变量有时会占很大,效率很低。

4.0、 int *p=&u; p存放的是变量u的地址,而&p的意思就是变量p本身的地址。

4.1、当要传参的个数比较多时,我们可以打包成一个结构体,传参的个数越多,其开销就更大. 

4.2    一个函数作用其实就是输入输出,参数可以作为输入,返回可以作为输出,但是当要返回多个输出时,这时候就不够用了,所以常常返回值用来判断程序又没有出错,而参数       就是当作输入输出的,输入时可以加const表示它没必要去修改,而输出都是指针,因为要改变它的值,只能采用地址传递这种方式。比如:char *strcpy(char *dest,const char *src)
    
四、C语言复杂表达式
4.1、在表达式中,要看符号的优先级和结合性。

4.2、在理解内存时,内存0地址在最底下,至上地址逐渐增加。

4.3、int *p;是定义的一指针变量p,而int  ( *p)[4];也是一个指针变量p;也可以这样想:凡是遇到(*p)什么的判断他是指针后,就可以说他是指针变量,包括函数指针。

4.4、一个函数 int max(int a ,int b);   则他的函数指针是 int ( *p  ) (int ,int );其意思就是定义这个类型的函数指针变量p; p=max是赋值,引用是p();则相当于max()调用这个函数。  函数指针必须和原函数的类型一样。

4.5 函数指针其实就是为了做结构体内嵌指针的,这样就构成了高级语言中的类。再一个就是上述4.4中p=&max;也是可以的,它和p=max,值和意义都是一样的,这个和数组有所区别,数组的a和&a的值虽然一样,但是意义完全不一样。int a[4];a有两层意思,第一层是数组名,&a表示整个数组的地址,第二层表示首元素的首地址。
 
4.6  int (*p[4])(int ,int)其意思是函数指针数组,一个4长度的数组,里面存了4个函数指针。

4.7 printf在做输出时,其机制是缓冲行来输出,即当遇到一个n后再打印出来,即使再多printf,没有遇到n,都不是一个一个打印。
     'r'是回车,'n'是换行,前者使光标到行首,后者使光标下移一格,通常敲一个回车键,即是回车,又是换行(rn)。Unix中每行结尾只有“

锐单商城拥有海量元器件数据手册IC替代型号,打造电子元器件IC百科大全!

相关文章