枚举类型:
声明方式:enum Coler{red,blue,yellow};
enum,是声明枚举类型的关键字
Coler,是这个枚举类型的名称,是可以省略的
一对花括号内是枚举类型的值。
编译器会把枚举的值赋值一个整数,从0开始,依次递增。
reb = 0;blue = 1;yellow = 2;
以下声明方式也是可以的:
enum {red ;blue = 5;yellow};
这个时候
red = 0;blue = 5;yellow = 6;
联合:
声明方式在结构上,除了关键字以外都和结构体一致
typedef union number{
int one;
char two;
}num;
联合类型的内存大小,是最大的那个成员变量所占内存大小,上述声明的num只占用4Byte。
所有的成员类型,都是共用地址的。
如果成员变量是一个结构体,结构体计算内存大小是按照整个结构体计算,代码如下。
typedef struct{
int row;
int col;
}Poit;
typedef union{
int num;
Poit poit;
}test;
int main(int argc,char** argv){
printf("%ld",sizeof(test));
return 0;
}
-----------------------------------
linxin@ubuntu:~/biaoc/day15$ ./Demo
8
二级指针:
一个指针变量中,存放着一个一级指针的地址,就叫做二级指针。
无论是一级指针还是二级指针,它们的内容都是一个地址的值。从数值的类型上来说都是地址数值。
声明方式:int** pp_num = NULL;
当一个二级指针指向一个一级指针数组的第一个元素的地址,那么就可以通过这个二级指针找到这个指针数组中的所有指针,这个时候这个二级指针可以代表整个指针数组。
在main函数的形式参数中,第二个参数是,char* argv[],这个参数记录的是,运行该函数时输入的字符串。
这个参数是一个char类型的指针数组,数组中的每一个指针都对应着一个字符串字面值的首地址。
可以用char** argv代替表示。
二级指针不代表二维数组!
无类型指针可能是一个二级指针
void* p = NULL;
int* p_num = NULL;
p = &p_num;
之前提到过,无论一级指针还是二级指针,它们记录的内容都是一个地址,都是地址类的值。
所以上述将一个一级指针的地址赋值给一个无类型指针是没有问题的。
当然,如果无类型指针想要使用*运算符,还是要强制转换成合适的类型的
*(char**)p
函数指针:
在C语言中,函数也是有地址的,函数名表示函数的地址。
void cp(int* p_num){
*p_num = rand()%36 + 1;
}
void (*func)(int*)
int num = 0;
func(&num);
如果有一个cp函数,原型如上,则可以根据原型的返回值和形参列表构造一个函数指针 *func
之后可以通过这个函数指针调用函数。
回调函数:
如果一个函数能够作为另一个函数的实际参数,则这个函数被称为回调函数。代码如下:
void turn(int* p_num){
*p_num = 0 - *p_num;
}
void print(int* p_num){
printf("%d ",*p_num);
}
void cp(int* p_num){
*p_num = rand()%36 + 1;
}
void for_any(int* p_num,int size,void (*p_func)(int*)){
for(int i = 0;i < size;i++)
p_func(p_num + i);
}
int num[] = {1,2,3,4,5};
for_any(num,5,turn);
for_any(num,5,print);
printf("\n");
for_any函数有一个函数指针的形参,这个函数指针类型和turn,cp,print三个类型相匹配,可以用于指向这三个函数,所以这三个函数可以被当作实际参数传入到for_any中。
动态分配内存:
C语言允许程序在运行过程中申请额外的内存,需要用到malloc函数。
该函数是在头文件stdlib.h中被声明,所以使用时需要包含该头文件。
malloc函数有一个整数类型的参数,它代表需要分配多少个字节的内存。
malloc函数的返回值是申请到的内存的首个字节的地址,返回的类型是void,所以要使用这个地址之前需要对返回值做一次强制转换。
综上所述,一次内存分配的语句如下:
typename* p_num = (typename*)malloc(size * sizeof(typename));
int* p_num = (int*)malloc(5 * sizeof(int));
这个样子就是分配5个int类型大小的内存空间。
分配内存是有可能失败的,这个时候malloc会返回一个NULL
所以每次申请内存之后,都需要用if语句来确认是否分配成功。演示代码如下:
int main(int argc,char** argv){
int* p_num = (int*)malloc(5 * sizeof(int));
if(p_num){
*p_num = 1;
*(p_num + 1)= 2;
printf("%d\n",*p_num);
free(p_num);
p_num = NULL;
}
return 0;
}
在程序执行过程中分配到的内存,在程序结束后计算机是不会直接收回的。
如果在程序结束之前一直不释放分配到的内存,程序结束后,计算机也不会收回,这块内存谁都用不了。这就是内存泄漏。
所以在程序之前,一定要释放分配到的内存。释放内存的函数如下:
free,它有一个参数,就是分配到的内存的首字节地址。
它会一次性释放完在这个首地址后分配到的内存。不会有释放一半留一半的选项。
被调用函数分配的内存,在没有释放前,调用函数也是可以使用的。所以有些应用,就是在被调用函数中申请地址,然后提供给调用函数使用,最后由调用函数负责释放。
不过这种使用情况,如果调用函数忘记释放,就内存泄漏了。