c语言1

来源:互联网 发布:探索者钢结构设计软件 编辑:程序博客网 时间:2024/05/30 02:51
C语言是一种介于低级语言和高级语言之间的一种中级语言
IDE工具          动作名词              输出结果
-----------------------------
编辑器         编辑              文本文件.c  .h
预处理器      预编译          处理后的文件
编译器        编译(汇编)  .obj(.asm)文件
链接器         链接               .exe文件
----------------------------//这是“动态”、“静态”的分界线
加载器        加载             加载到内存
运行器         运行

编辑阶段:此时文件的类型并未发生变化。
预编译的文件包括:#include<头文件> #define (宏定义) //宏定义只是简单字符的替换
编译阶段:只对单个文件进行编译,不关心是否有函数声明等问题。
链接阶段:对多个文件进行连接操作,此时判断各个语句是否合法有效。

数据类型

数据类型的意义:定义了数据占用的内存空间大小;定义了数据的取值范围;定义了数据在内存中的存取格式;决定了数据的运算规则;为编译器提供了检查依据。
数据类型起作用的时机是在编译时。
数据在内存中存放的最小单位是一个字节。多字节的数据在内存中存放的方式包括大端对齐和小端对齐。1、小端对齐,将低位存放在低地址;2、大端对齐,将高位存放在低地址。利用共用体验证当前存储是大端对齐还是小端对齐。大端对齐和小端对齐针对的是多字节存储。
例如,对于一个32位的数0x12345678
小端对齐的存储方式:(高地址)12 34 56 78(低地址)
大端对齐的存储方式:(高地址)78 56 34 12(低地址)

结构体:
为了加快CPU的存取速度,C编译器在处理数据时,把结构体变量中的成员的摆放按照某个对齐原则规划,这就是边界对齐。边界对齐一般满足三个准则:1、结构体变量的首地址能够被其最宽基本类型成员大小与对齐基数中的较小者所整除;(VC默认对齐基数是8)。2、结构体每个成员相对于结构体首地址的偏移量都是该成员大小与对齐基数中的较小者的整数倍,如有需要编译器会在成员之间加上填充字节。3、结构体的总大小为结构体最宽基本类型成员大小与对齐基数中的较小者的整数倍,如有需要编译器会在最末一个成员之后加上填充字节。

“对齐”的规则补充:由于结构体的成员可以是复合类型,比如是另外一个结构体
1、在寻找最宽基本类型成员时,应当包括复合类型成员的子成员,而不是把复合成员看成一个整体。
2、但在确定复合类型成员的偏移位置时则是将复合类型作为整体看待。(规则2:偏移量都是该复合类型成员大小与对齐基数中的较小者的整数倍)

指针类型;
void 表示无类型,只能用于指针和函数;
地址都是4个字节,sizeof(指针类型变量)和 指向的数据类型无关都是4个字节
char *p;
int *q;
sizeof(p)=4;
sizeof(*p)=1;
sizeof(q)=4;
sizeof(*q)=4;
指针的概念:内存中每个字节有唯一编号,这就是“地址”
变量的访问方式:(1)直接访问-使用变量名进行存取(2)间接访问-通过该变量的地址来访问
指针是用来存放其他变量地址的变量(且只能存放地址),是一种特殊形式的变量;其value是别人的地址;可以定义为void*;间址访问才有意义。
指针是一种容纳地址的变量,通常也叫指针变量,统称指针,而地址则是内存单元的编号是一个常量
运算符:&:取址运算符(只能作用于变量)、*:指针运算符(间接访问运算符),或指针定义符
指针有以下几种运算:赋值、*运算、&运算、加/减一个整数、自增、自减、求差、比较(地址运算+或者-系统会默认加上*或者/sizeof(类型))
p+(-)n:将指针从当前位置向前(+n)或回退(-n)n个数据单位(指针指向的类型),而不是n个字节。显然++p/p++和—-p/p—-是p+/-n的特例(n=1)。
p1-p2:俩个指针之间的数据个数,而不是指针的地址之差
char **p1;是普通二级指针
char (*p2)[5]是指向char[5]数组的指针
char *p3[5]是以char *为基本元素类型的指针数组
指针与const

数组类型
数组不包括动态分配,在编译时分配空间,所以数组的大小是一个常量
数组时一种数据结构,是线性表的一部分
数组访问的本质是:首地址+偏移量(偏移量=下标值*sizeof(数组元素类型))
*(首地址+偏移量)  --*间址运算符
数组的特点:存储空间连续、元素之间有序、元素类型相同、元素个数固定(除了在堆上分配)、数组元素无名。
数组名代表数组的首地址,是不可修改的常地址。
C语言将多维数组的访问变成了多次对一维数组的访问。所以在C语言中根本没有多维数组
数组名作函数实参时,不是把数组的值传递给形参,而是传地址。这俩个数组就共同占用同一段内存单元.
当数组作为函数的参数进行传递时,该数组自动退化为指针。
多维数组加一个*降一维;
访问方式:直接访问--用变量名访问、间接访问--用地址、指针访问
[]是一个变址运算符,int *p,a[10];p=a;*(p+i)、*(a+i)就可以取到数组中的第i个元素的值

函数类型
函数类型包括返回值和行参列表;
函数调用的步骤:1、跳转到代码区内函数所对应的首地址2、创建函数栈帧(分配内存空间)3、进行参数传递,先计算实参表达式的值,再赋给形参变量。4、执行函数体5、返回调用点并交出计算结果,即函数调用表达式的值6、释放运行栈
传址的作用:传入大量数据、传入大型数据、返回多个数据。
数组名作函数参数时,自动退化为指针。函数得到的仅仅是数组的首地址,而不是像传值一样拥有自己的数据存储空间;因此主函数和子函数是对同一个数据空间(数组)进行操作,形参的任何改变会导致实参值的改变

修饰变量的关键字:volatile、const、extern、register、static
volatile
int x=0,val1,val2;
val1=x;
…..//一些不使用x的代码
val2=x;
 编译器可能将x优化到寄存器当中,而x是易变的变量,在俩次访问中可能x的值变化了,则访问x应该使用内存中的“原版”
volatile int x;//对该变量不进行寄存器优化
const
可以保护被修饰的东西,防止意外的修改,增强程序的健壮性
1、2、3都是常指针,指针永远指向同一个内存地址
1、int const i=10;
2、const int i=10;
3、int *const p=&i;
4、5是指向常量的指针,不能通过指针p来改变变量i
4、const int *p=&i;
5、const int * const p=&i;
register
static 
修饰变量--该变量变成静态变量
如果是静态局部变量,影响变量的生存期(和普通局部变量比较起来更“长命”),作用域不变,仍然由函数块域限制(即“{}”限制)。静态局部变量和程序一样长命由栈区转移到静态区;静态局部变量只初始化一次
如果是全局静态变量,生存期不变(和全局变量比较起来依然“长命”),但将变量访问本地化(作用域在本.c文件)。全局静态变量的作用域变小。
extern
修饰变量  extern int i;变量声明,不是定义,随后可能要使用该变量,无论该变量在其他.c中实现(定义),还是在本.c中实现(定义)都可以继续访问变量。
修饰函数 extern void fun(); 要引用某函数的声明,不是实现(定义)。引用后可以调用该函数,无论改函数在其他.c中实现(定义),还是在本.c中实现(定义)


内存
内存的划分:主要分为数据区和代码区;
数据区包括栈区、静态区、堆区;栈区存放程序的局部变量和形参,函数调用时临时创建的;静态区存放程序的全局变量和静态变量,在编译阶段完成;堆区存放程序动态申请的数据。代码区存放程序的代码和常量。

栈区(stack区)
特点:由系统按栈原则管理;短命,函数执行完则释放;用户无法干预变量的诞生和消亡。
当全局变量和局部变量同名时,在函数中引用,局部屏蔽全局。
静态区(static区)
特点:不按栈原则管理,长命,但局部静态变量仍受“作用域”的制约
static局部变量只做一次初始化
堆区(heap区)
特点:长命,无名;用户干预变量的诞生和消亡;在程序运行时才能动态分配内存;申请可能失败。
代码区(code区)
特点:存有程序的所有执行代码和常量;

堆空间的使用
C语言的动态内存分配核心函数有:malloc()、calloc()申请堆内存 ;free()释放堆内存;使用这三个函数必须包含头文件stdlib.h
malloc()函数原型:void* malloc(size_t size);
功能:从堆内存中分配连续的大小为size字节的内存单元,这些单元没有类型。
动态申请堆内存,参数只有大小一个参数;
使用指针类型的原因是保证分配内存的首地址;
使用void*d是因为不知道存储的数据是什么类型,到具体使用时可以使用(类型*)把返回值强制类型转化为特定的类型。
返回值:若有足够的内存,则返回指向分配的内存空间的首地址(void *类型),否则返回NULL。
calloc()函数原型:void* calloc(size_t num,size_t size);申请num个size大小的空间(以字节为单位)
功能:申请分配一大块内存,并将该块内存全部“清零”。
返回值:若内存足够,返回一个指向新分配内存地址的void*类型的指针,否则返回NULL。
free()函数原型:void free(void *memblock);
功能:用来释放被malloc()或calloc()分配的内存空间。
注意:传入指向堆内存空间的首地址,释放的事整个内存块,而不是指向该块的指针类型的大小。在程序的执行过程中,函数体内的局部指针变量在函数结束时会自动消亡,但它所指向的动态分配的内存却不会释放,需要free()函数来完成该任务。
堆空间使用的标准:1、定义一个堆空间2、分配空间3、判断是否分配成功4、释放空间5、清空指针
如果存在内存越界会导致释放时找不到信息,释放失败。
注意事项:1、数组或指针的下标越界2、内存释放不代表指针消亡(free(p);p=NULL;)3、指针消亡不代表内存释放4、不能只释放块的一部分空间5、避免使用野指针6、避免内存泄漏(给指针赋值:strcpy(p,”hello”);)

输入输出
C语言不提供输入输出语句,输入输出操作由函数来实现。
scanf注意事项:变量必须是一个地址。在读入字符串时,要确保有足够的空间存放读入的字符串(包括字符串结束符‘\0’),否则会覆盖内存中的其他数据。
1、scanf()函数接受输入数据时默认不采用空格、回车、跳格这些空白字符,但使用%c读取数据时除外。
2、在控制字符串中添加一个或多个空白字符表示忽略空白字符录入
循环录入中有多个scanf()时一定要加空格 scanf(“ %c”,&i);
scanf(“%[]”);格式控制符,输入非法字符则结束
%[指定可输入字符集] %[^指定不可输入字符集]
%s格式输入字符串遇到空格则结束
gets:读入一串字符(可以读空格)。gets没有拦截。最多可读入n-1个字符,最后一定是’\0’结尾。
printf()
%md-输出的数据共占m列,右对齐,数据不足m列,左补空格
%-md-输出的数据共占m列,左对齐,数据不足m列,右补空格

预处理:
宏:只是单纯的替换,宏也有作用域

位操作
基本位操作
&位与、|位或、~位反、^位异或(相同为0,不同为1)、<<左移(无符号数左移一位相当于该数乘以2,高位溢出丢弃,低位补0)、>>右移(无符号数右移一位相当于该数除以2溢出位丢弃高位补0,有符号数例外)
使用:
(1)判断int 型变量a是奇数还是偶数  a&1=0-偶数 a&1=1-奇数
(2)取int型变量a的第k位 a>>k&1
(3)将int型变量a的第k位清0 a=a&~(1<<k)
(4)将int型的第k位置1  a=a|(1<<k)
(5)int型变量a循环左移k次 a=a<<k|a>>32-k  (设sizeof(int)=4)
(6)int型变量a循环右移k次 a=a>>k|a<<32-k  (设sizeof(int)=4)
0 0
原创粉丝点击