C语言条件预处理命令
1 /*
2 格式:3 #ifdef 标识符4 程序15 #else6 程序27 #endif8 标识符已经定义时,程序段1才参加编译9 应用:如调试版本,发行版本,便于调试10
11 */
12 #include
13 intmain()14 {15 #ifdef ABC // #define ABC 116 printf("程序一");17 #endif
18 printf("hello world");19 return 0;20 }
类型修饰符register (不常用)
register int a;
内存(存储器), 寄存器
限制变量定义在寄存器上的修饰符,定义一些快速访问的变量,编译器会尽量的安排CPU的寄存器去存放在这个a。如果寄存器不足时,a还是放在存储器中。
类型修饰符volatite
告知编译器编译方法的关键字,不优化编译
修饰变量的值的修改,不仅仅可以通过软件,也可以通过其他方式(硬件外部的用户)
类型修饰符const
常量的定义,只读的变量,参考收藏的文章
指针+const
//内存属性//1、内存操作的大小//2、内存的变化性,可写可读
const char *p; //常用这个 字符串 “hello world ” "aaa"
char const *p; //p指向的内容可读不可写
char *const p; //硬件资源 LCD 固定地址内容可变
char *p const;const char *const p; //ROM 什么都不变
总结:const在char的左边那就是不能修改地址中的值,在右边就是不能指向其他地址,左右都有那就是既不能修改地址的值也不能指向其他地址。
动态内存管理
malloc:
函数原型:void *malloc(size_t size);
功能:malloc函数向系统申请分配size个字节的内存空间,并返回一个指向这块空间的指针
返回值:成功 void指针(void *)
失败 NULL
函数原型: void free(void *ptr)
功能:释放ptr参数指向的内存空间。该空间必须是由malloc、calloc或realloc函数申请的
返回值:无
内存泄漏:
#include #include
int main(void)
{while(1)
{malloc(1024);
}return 0;
}
结果:卡顿
导致内存泄漏主要有两种情况:
隐式内存泄漏(即用完内存块没有及时使用free函数释放)
丢失内存块地址
以mem开头的函数包含在string.h头文件中:如memset,memcpy
void *memset(void *s,intc,size_t n)
总的作用:将已开辟内存空间 s 的首 n 个字节的值设为值 c
void *memset(void *s,intc,size_t n)
总的作用:将已开辟内存空间 s 的首 n 个字节的值设为值 c
#include #include#include
#define N 10
int main(void)
{int *ptr=NULL;inti;
ptr=(int *)malloc(N*sizeof(int));if(ptr==NULL)
{
exit(1);
}
memset(ptr,0,N*sizeof(int));for(i=0;i
{
printf("%d",ptr[i]);
}
putchar('');free(ptr);return 0;
}
另外还有calloc:申请并出示化一系列内存空间 realloc:重新分配空间
结构体:可以将多种数据类型组合起来的结构
声明方式:
1 struct 结构体名称{2 类型 变量名;3 }结构变量1, 结构变量2;
结构体的大小:
structst01{charc;
};sizeof(struct st01);//c++ 直接st01就行//输出结果为1
structst1{charc1;charc2;inta;
};structst2{charc1;intalcharc2;
};sizeof(struct st1);//8
sizeof(struct st2);//12
structst3{char arr[5];intb;shortc;
};structst4{char arr[5];shortc;intb;
};sizeof(struct st3);//16
sizeof(struct st4);//12
structst5{charc1;charc2;doublea;
};structst6{charc1;doublea;charc2;
};sizeof(struct st5);//16
sizeof(struct st6);//24
结论:
结构体定义的时候,变量成员的顺序会影响结构体的大小
对齐:成员变量以什么样的方式排列,紧密排列还是松散,中间是不是有间隔。
大小影响因素:成员变量的大小;对齐方式
编译器对于对齐方式,可以选择的,VS默认是8字节对齐的。字节对齐:1,4,8,16;不同类型变量的对齐
如果编译器的对齐方式大于4字节:int:4字节,必须以字节的倍数分配地址;如果结构体里面有int,那么结构体的大小就是4的整数倍。
如果short,double,同样的道理;
如果有相同类型的变量呢,一定要放在一起,会减少结构体的空间。
结构体定义,变量类型从小到大的顺序比较合适(建议)
程序中设置内存对齐#pragma pack(n) 如:#pragma pack(1) //1个字节对齐,会紧密排列
关键字union
union 关键字的用法与struct 的用法非常类似。
union 维护足够的空间来置放多个数据成员中的“一种”,而不是为每一个数据成员配置空间,在union 中所有的数据成员共用一个空间,同一时间只能储存其中一个数据成员,所有的数据成员具有相同的起始地址。
这里需要考虑存储模式:大端模式和小端模式。
大端模式(Big_endian):字数据的高字节存储在低地址中,而字数据的低字节则存放在高地址中。
小端模式(Little_endian):字数据的高字节存储在高地址中,而字数据的低字节则存放在低地址中。
枚举类型enum
以下代码定义了这种新的数据类型 - 枚举型
enum DAY
{
MON=1, TUE, WED, THU, FRI, SAT, SUN
};
(1) 枚举型是一个集合,集合中的元素(枚举成员)是一些命名的整型常量,元素之间用逗号,隔开。
(2) DAY是一个标识符,可以看成这个集合的名字,是一个可选项,即是可有可无的项。
(3) 第一个枚举成员的默认值为整型的0,后续枚举成员的值在前一个成员上加1。
(4) 可以人为设定枚举成员的值,从而自定义某个范围内的整数。
(5) 枚举型是预处理指令#define的替代。
(6) 类型定义以分号;结束。
指针
指针是一个特殊的变量,它是存放地址的。
四要素:指针的类型、指针所指向的类型、指针的值或者叫指针所指向的内存区、指针本身所占据的内存区。
//*:取值操做符//&:取址操做符 &与*优先级相同
int i=2000;int *pointer;
pointer=&i;
printf("%d",*pointer);
指针变量和指针:
知道了一个变量的地址,就可以通过这个地址来访问这个变量,因此,又把变量的地址称为该变量的“指针”
C语言可以定义一类特殊的变量,这些变量专门用来存放变量的地址,称为指针变量。
注意:指针变量的值(即指针变量中存放的值)是地址(即指针)。
float *pointer_1;//指针变量名是pointer_1,而不是*pointer_1
几种常用格式:
pointer=&a;&*pointer //与&a相同,即变量a的地址】
*&a //先&a,得到a的地址,再进行*运算。即&a所指向的变量,也就是变量a
(*pointer)++ //相当于a++
1 #include
2 voidmain()3 {4 int *p1,*p2,*p,a,b;5 scanf("%d %d",&a,&b);6 p1=&a;7 p2=&b;8 if(a
17 }
多级指针:存放地址的地址空间,更多的是描述线性关系。
char **p;(圆圈p) p[m]=NULL结束
指针数组
char *a[100]sizeof(a)=100*4; //一个指针4个地址
指针数组:首先它是一个数组,数组的元素都是指针,数组占多少个字节由数组本身的大小决定,每一个元素都是一个指针,在32 位系统下任何类型的指针永远是占4 个字节。它是“储存指针的数组”的简称。
数组指针:首先它是一个指针,它指向一个数组。在32 位系统下任何类型的指针永远是占4 个字节,至于它指向的数组占多少字节,不知道,具体要看数组大小。它是“指向数组的指针”的简称。、
具体可以参考收藏的文章。
数组越界
所谓的数组越界,简单地讲就是指数组下标变量的取值超过了初始定义时的大小,导致对数组元素的访问出现在数组的范围之外,这类错误也是 C 语言程序中最常见的错误之一。
C 语言并不检验数组边界,数组的两端都有可能越界,从而使其他变量的数据甚至程序代码被破坏。
1 voidtest1()2 {3 char string[10];4 char* str1="0123456789";5 strcpy(string, str1);6 }
string数组越界,因为字符串长度为10,还有一个结束符‘