C语言学习笔记(四)
结构体 struct关键字
** 结构体声明中包含的变量声明语句不会真正分配内存,它们只是用来表示子存储区的类型所以不能进行初始化
结构体类型可以创建结构体变量,结构体变量才正真分配内存,
typedef关键字可以用来给类型起别名
structperson{ typedefstruct /*person*/{
}; }SPR;
typedefstruct person SPR;
SPRprn1;
同类型结构体变量之间可以直接赋值
结构体指针
当结构体指针和结构体存储区捆绑后可以在结构体指针名称后加->再加子存储区名称表示这个子存储区
结构体变量可以作为形式参数使用,但会造成时间和空间的浪费
数据对齐规则
内存中一个存储区的地址必须是它自身大小的整数倍(double类型存储区的地址只需要是4的整数倍)
结构体内部子存储区通常也需要遵守数据对齐规则
数据对齐可能导致结构体内部不同子存储区之间有空隙
结构体存储区的大小必须是其中包含的占地最大的基本类型子存储区大小的整数倍
(如果这个基本类型是double类型则结构体存储区的大小之需要是4的整数倍)
这个规则叫数据补齐
数据补齐会导致结构体最后有一些浪费的字节
枚举( enum )
枚举类型存储区就是整数类型存储区它里面只能记录有限的几个整数
声明枚举类型的时候需要提供一组名称,每个名称对应一个整数,只有这些整数可以记录在
+枚举类型的存储区里不同枚举类型所能记录的数字范围不同
enum {CHUN,XIA,QIU,DONG};
CHUN = 0 ; XIA=1; QIU=2; DONG=3;
enum {CHUN,XIA=5,QIU,DONG};
CHUN = 0 ; XIA=5; QIU=6;DONG=7;
计算机里使用从0开始的一组连续的整数代表枚举类型中的名称
联合(union )
union tmp{
charar[2];
inta;
};
联合存储区可以当作多种不同类型的存储区使用
联合的所有子存储区所占的位置互相重叠,他们开始地址一样
联合存储区的大小就是最大子存储区的大小
二级指针(int**p )
用来记录普通类型存储区地址的指针叫一级指针
用来记录一级指针地址的指针叫二级指针
int num =0;
int * p_num = #
int ** pp_num = &p_num;
**pp_num = 10; --> num == 10;
*pp_num = NULL;
二级指针可以代表指针数组,不能代表二维数组
无类型指针有可能实际代表一个二级指针
二级指针通常作为形式参数使用,它可以让被调用函数使用调用函数提供的一级指针存储区
函数指针
c语言里函数也有地址
函数名称可以代表函数地址
int add(int num, int num1)
{
}
int main()
{
int(*p_func)(int, int)=NULL; //函数指针名称
p_func=add;
p_func(3,7);
}
函数指针也分类型,不同类型的函数指针适合与不同类型的函数捆绑
函数指针可以作为形式参数使用
可以作为实际参数使用的函数叫回调函数
1 #include <stdio.h>
2
3 voidprint(const int * p_num, int size)
4 {
5 int num = 0;
6
7 for(num = 0; num<=size-1; num++)
8 {
9 printf(" %d ", *(p_num+num));
10 }
11 }
12
13 void print_cb(int * p_num)
14 {
15 printf(" %d ", *p_num);
16 }
17
18 void brack(int * p_num)
19 {
20 *p_num = 0-*p_num;
21 }
22
23 void for_each(int *p_num, int size, void(*p_func)(int*) )
24 {
25
26 intnum = 0;
27 for(num = 0; num<=size-1; num++)
28 {
29 p_func(p_num+num);
30 }
31 }
32
33 int main()
34 {
35 intarr[] = {1, 2, 3, 4, 5};
36 print(arr, 5);
37 printf("\n");
38 for_each(arr, 5, print_cb);
39 printf("\n");
40 for_each(arr, 5, brack);
41 for_each(arr, 5, print_cb);
42
43 printf("\n");
44 return 0;
45 }
动态分配内存#include<stdlib.h>
int * p = (int*)malloc(sizeof(int)); //分配的是第一个字节的地址,分配失败就返回NULL
if(!p)
{
动态内存分配空间失败
} //malloc返回的是一个无类型指针,所以要先进行强制类型转换
free(p); //内存泄露了
p=NULL;
strlen (array); 计算的是一个数组字符串实际使用的大小
sizeof (array); 计算的是一个数组或字符串在内存中申请的空间大小
eg: char str[10] = {};
sizeof(str)/sizeof(str[0]) == 10
strlen(str)/sizeof(str[0]) == 0
在获取一个数组的大小时,不要针对一个指针应用sizeof运算符
对变量起作用的属性有两个:数据类型和存储类型
存储类型决定着该变量的存储区域,存储区域又决定这变量的作用域和生命周期
内存的分类
静态内存:程序在编译的时候就已经分配好,这块内存在程序的整个运行期间都存在
动态内存:程序在运行的时候创建的,包括对内存,栈内存
内存分配方式相应分为:
静态分配:
编译时已经确定并初始化了
用户无法干预
不按栈原则管理,但仍受“作用域”的制约
存有 全局变量,局部静态变量,和常量
栈式分配,
堆式分配
*
* 全局变量
* 定义在主函数之外的变量,有外部链接性,作用域为整个工程,在其它文件中如要使用必须
* +使用extern全局变量名声明就可以使用
* 全局静态变量
* 定义在函数之外,且用static修饰的全局变量,作用域只有声明此变量的文件。未初始化自动为零
* 局部变量
* 程序块中申请的变量,作用域只有这个程序块
* 局部静态变量
* static修饰的局部变量,全局区分配内存,作用域与局部变量一样,未初始化自动为零
* 静态函数
* static修饰的函数,只能被声明它的文件被识别,不能被其它文件使用
*
* 代码区:
* 存放代码函数的区域
* 只读常量区:
* 存放字符串字面值和const修饰的全局变量
* 静态区(全局区):
* 保存自动全局变量和static变量(包括static修饰的全局变量和局部变量).静态区的内容在总个程序
* +的生命周期内部都存在,由编译器在编译的死后分配的,静态变量都会初始化为零
* 静态变量的初始化只在程序开始执行一次
* BSS段:
* 用于存放未初始化的全局变量区域,BSS段在main函数执行之前会清0;
* 栈 区:
* 保存均不变量,栈上的内容之在函数的范围内存在,当函数运行时结束,这些内容也会自动被销毁,其
* +特点是效率高,但空间大小有限
* 堆 区:
* 由malloc系列函数或new操作符分配的内存,其生命周期由free或delete决定的。在没释放之前一直存在,
* +直到程序结束,其特点是使用灵活,空间比较大,但容易出错。
*
linux 系统中调用sleep()函数之前最好用"\n"清空缓冲区
a=0; a = !a; a == 1; (!0 == 1 )
c语言中余数的符号与被除数的符号一致,(被除数*除数=商……余数)
#include <unistd>
Linux系统下C 程序获取当前程序绝对路径函数
getcwd(buffer,sizeof(buffer));
< 续:C语言学习笔记(五)>