C基础入门

一、基本概念

1、C语言区分大小写;
2、注释/*里边的所有内容都是注释*/,或者//单行注释;
3、printf() 打印,f表示format;scanf()输入;
4、变量必须要有声明,一次声明可同时声明多个变量并同时赋初值,每个变量之间用,号隔开;(当试图访问未初始化的变量时,可能产生无意义的数值或者让程序崩溃)
5、定义常量约定全使用大写字母(例:#difine NUMBER 11)
6、变量命名(也叫标识符)规则:
(1)可以含有字母、数字、下划线;
(2)只能以字母或下划线开头;
7、多行代码可用\符号进行连接;
8、把C程序转换为机器可执行的形式,通常包括预处理、编译、链接三个步骤;
预处理:预处理器执行以#开头的指令;
编译:把程序翻译成机器指令;
链接:把由编译器产生的代码和所需要的其他附加代码整合在一起;
9、可以把C程序看成是一连串的记号(token),包括:标记符、标点符号、关键字、字符串字面量;
10、标识符的长度理论上是没有限制的,但超过63(C99)个字符编译器可能无法识别;
11、逻辑运算符(!,&&,||)运算的结果是0和1,会将任何非零值操作数作为真值处理,任何0值操作数作为假值处理;
12、switch语句对分支的顺序没有要求,可以把default放在最前边,多个分支语句可以放在同一组执行语句的前边,用于表示这些情况都执行这相同的操作(例case 1: case 3: case 4: 语句;)
13、#define TRUE 1 定义一个常量;

 

二、数据类型

int                  整型,默认是有符号的;读写:%d
unsighed int          无符号整型,长度为2的32次方,但在老的CPU上也可能是16位;读写:%u/%o/%x
short int            短整型,默认是signed,即有符号的;读写:%hd,无符号读:%hu/%ho/%hx;
unsigned short int     无符号的短整型,short和unsigned的位置可互换;长度为2的16次方;
long int            长整型;为了强制编译器把常量作为长整数来处理可以在后边加一个L或l(如:14L);读写:%ld,无符号的读写:%lu/%lo/%lx
unsigned long int      无符号的长整型,长度为2的64次方;为了指明常量为无符号的可在常量后加U或u;
C中整型包括8进制,10进制,16进制,8进制以0开头,16进制以0x开头(不区分大小写),且这都只是整数的书写形式,存储都是以2进制存储的,不同的进制可同时使用(如:10+023+0x21)

float                单精度浮点数;精度为6位数字;浮点常量必须包含小数点或指数,但小数点前后可为空,会自动补齐一个0; 读写可用%f/%e/%g
double               双精度浮点数;精度为15位数字;读:%lf/%le/%lg;写:%f/%e/%g;
long double          扩展精度浮点数;读写:%Lf/%Lg/%Le;

char                字符类型(实质是int 类型的);读写:%c,对于单个字符的读写可用getchar()和putchar()函数来实现;

1、数据的隐式转换级:short int -> unsigned short int -> int -> unsigned int -> long int -> unsigned long int -> float -> double -> long double
2、强制类型转换:(类型名)表达式 (例:(int)x;)
3、类型定义: typedef 类型名 自定义类型名;使用后自定义类型名就可以作为一个和系统类型一样的类型使用;(另一种方法可使用宏来将一个已有的类型名绑定到自定义名字上,如 #define BOOL int)
4、sizeof()函数可获取程序存储相应数据所需空间的大小;

(一)数组array

1、声明: type name[num];
2、可在声明时给定初值{1,2,3},如果给的初值数量不及num,会自动以0来补齐,但初值不能全为空{},至少需要有一个元素;
3、如果给定了初值可以不指定num,C会自动根据给定的初值数量来确定num;
4、给定初值时可用{[2]=6,8,[7]=7}的方式来给指定位置的元素赋值;但这样会让初值赋值位置跳到指定位置上,如上边的8赋给的位置就是3,其他位置都以0补齐;如果没有给定num,上例中自动生成的num就会是8;
6、C语言不要求检查下标的范围,所以即使给出了超出索引的下标,程序也不会报错;
7、使用scanf("%d",&a[i]);可对某个元素直接使用取址符;
8、使用sizeof(a)/sizeof(a[0])来取得一个数组的元素个数;
9、数组可以是多维的(例:int x[2][3],给此二维数组初值{{1,2,3},{2,3,4}},也可省略里边的花括号,但这样比较危险,程序会依次给相应位置的元素赋值;)
10、不能使用数组a=数组b的方式把b的值直接复制到a,最简单的方法是使用一个循环,使用它们的每一个元素都相等才行;或者使用memcpy(a,b,sizeof(a))函数进行复制;

(二)结构、联合、枚举

1、结构的声明:

struct structName {
  typename name1;
  typename name2;
  ...;
}structN1,
structN2 = {value1,value2,...},
structN3 = {.name1 = value3, .name2 = value4,...}
structN4 = {.name1 = value5,value6,...};

每个结构都有一个独立的命名空间,所以不同结构都可以使用相同的变量名字;

结构也可以不要structName,但是这样如果有多个结构就无法区分;
可以在声明结构的同时实例结构并初始化,如structN1,初始化方式可如示例的几种,初始化中未涉及的成员值都会被设为0;也可以后再实例(示例:struct structName structN5,每次都需要加上关键字struct)
上例中的.name1式样的点号和成员名称的组合称为 指示符,点号的运算优先级高于取址符&,所以 "&structN1.name1"表示的是structN.name1的地址;
声明结构时最后的分号";"是必不可少的,即使声明同时一个实例也没有,也必须要在}号后加一个分号
2、用typedef来定义一种新的类型名:

typedef  struct {
    typename name1;
    typename name2;
    ...;
}structName;

这样一个structName就相当于一种数据类型,实例时可如int一样使用,同时也一定不能在前边加struct关键字了;不过我们一般不使用这种方式声明结构;
3、数组可以有结构作为元素,结构也可以包含数组和结构作为成员;
4、联合的声明:

union{
    typename name1;
    typename name2;
    ...;
}unionN1,
 unionN2{.name2=value1};

联合可以有多个成员,但他只会存储一个成员的值,当给基中一个成员赋新值的时候,其他成员的值就会被抹掉,因为一个联合只有所有成员中最大成员所需要存储空间的大小,同时只能存储一个元素,所以在初始化union时只能初始化一个成员。
5、枚举的声明:

enum enumName{
    NAME1,
    NAME2 = const,
    ...
}enumN1;

和struct类似,在以后实例的时候需加上关键字enum(如:enum enumName enumN3;)
也可以用typedef来定义一个类型:
声明:typedef enum { NAME1,NAME2 }enumName;
这样在实例这个枚举时也不需要在前边加关键字enum了;
6、枚举常量的名字的作用域范围是全文件,不同于结构或联合的独立作用域;但是如果枚举常量声明在函数体内,那么它的常量对外部函数来说是不可见的;

三、格式化输入、输出(printf,scanf)

1、格式串包含普通字符和转换说明,转换说明以%开头;
2、转换说明格式:%-m.pX
m表示显示的最少字符数量;.p表示显示小数点后的位数,依赖于m;-表示右对齐,如果没有则默认左对齐;
3、%d 表示十进制整数,如果scanf()用%i可匹配八进制和十六进制的整数;
%e 表示指数,
%f表示定点十进制浮点数,
%g 表示指数形式或者定点十进制形式浮点数;
4、scanf() 需使用取址符&来对所输入的值进行变量名关联; 例:scanf("please enter two number %d,%d",a,b)

四、循环

1、for循环中的条件表达式都可以省略,当省略掉第一个和第三个表达式的时候就和while循环一样的效果;
2、for语句声明的变量不可以在循环外访问;
3、for语句可声明多个变量,只要它们的类型相同;
4、break语句只能跳出一层嵌套;
5、goto语句可以跳转到函数中任何有标号的语句处(标号语句示例,标识符(自定义):语句);goto语句和执行语句必须在同一个函数中;
6、for循环的变量改变是在所有语句都运行完毕后再执行的。

五、函数

1、函数不能返回数组;但是可以数组为参数传递给函数,但不会检查数组长度,所以数组参数不用给长度,但多维数组除了第一维,其他都需要给定长度;
2、C语言允许在实际参数的类型与形式参数的类型不匹配的情况下进行函数调用,编译器会执行默认的实际参数提升;
3、在main函数中执行return会终止程序,在任何地方调用exit函数都会终止程序;
4、C语言允许函数递归调用函数本身;
5、不允许一个函数的定义出现在另一个函数体中(嵌套);
6、函数原型中的形式参数的名字可以与函数定义中给出的名字不同;
7、局部变量的存储单元在包含该变量的函数被调用时分配,函数返回时收回分配,称为自动存储期限;如果声明时加上static则不会回收,称为静态存储期限;
8、局部变量的作用域只在本函数内,想要一个全局的变量则需要将变量声明在函数外,即main函数中;静态局部变量虽然能一直保持,但也只对本函数可见,其他函数是不可使用的;

六、指针

1、指针变量可以和其他变量一起出现在声明中;一个指针变量甚至可以指向另一个指针,即指向指针的指针。
2、指针变量可以在声明同时对它进行初始化(int *p = &i), int * 属于一个整体,用于表示p是一个指针。
3、指针可以指向数组元素,数组元素之间的地址差值就是它们索引值的差;
4、后缀++的优先级高于*;
5、可用数组的名字作为指向数组第一个元素的指针;声明a是指针就相当于声明它是数组,编译器把这两类声明看作是完全一样的;
6、可以把数组名用作指针,但不能给数组名赋新的值,试图使数组名指向其他地方是错误的;
7、用于指针算术运算的整数需要根据指针的类型进行缩放;

七、字符串

1、C语言把字符串字面量作为字符数组来处理;只要保证字符串是以空字符结尾的,任何一维的字符数组都可以用来存储字符串(但字符串并不要求一定要有空字符);
2、试图改变字符串字面量会导致未定义的行为;
3、字符串变量的声明中可以省略它的长度;
4、转换说明%s允许printf函数写字符串。其实也可以用printf(str)来打印字符串,但如果str中含有%则会使printf认为是转换说明的开始;%.ps可以指定显示的字符数量为p,%ms会在大小为m的字段内显示字符串,对于超过m个字符的不会被截断,而会显示整个字符串,如果不足m个则会右对齐输出,如要左对齐则可以在m前加一个减号;
5、put(str)显示字符串函数;gets(str)读取字符串,它在开始读取字符串之前跳过空白字符(scranf函数会跳过),gets函数会持续读入直到找到换行符才停止(scanf会在任意空白符处停止);
6、在scanf函数中读取字符串不需要对变量名前加&取址,因为字符串变量名本身就是指针;可用%ns来指定字符串可存储的最大数量,这样更安全;
7、getchar()读取单个字符,且会把它读取到的字符作为int类型的值返回;
8、字符串的复制,直接让一个字符串变量名等于另一个字符串或字符串变量名是错误的,必须进行逐个的赋值;
或调用函数strcpy(str1,str2),且它会返回str2的值;
strncpy(str1,str2,sizeof(str1)-1)也是字符串的复制,它可以指定从str2复制出字符数量的最大长度;
9、strlen(str) 求字符串的长度;
strcat(str1,str2) 字符串的拼接;
strcmp(str1,str2) 字符串的比较,返回一个小于、等于或大于0的值;
10、相邻的字符串面量会被合并;

八、预处理指令

1、预处理器是一个小软件,处理预处理指令;
2、预处理指令都是以#号开始,但并不需要一定在一行的行首,只要#前有空白字符就行,指令的符咒之间可以插入任意数量的空格或水平制表符;
3、指令总是在第一个换行符处结束,且可以出现在程序的任何地方;
4、指令主要有三种类型:宏定义(#define,#undef)、文件包含(#include)、条件编译(#if,#ifdef,...)
5、简单的宏格式:#define 标识符 替换列表
功能即用标识符来代替替换列表的内容,替换列表可以包括:标识符、关键字、数值常量、字符常量、字符串字面量、操作符、排列;(#define N 100; 是错误的,它将N定义为100和;两个记号);
6、用#define来命名的优点:1)程序更易读;2)程序更易修改;3)可以帮助避免前后不一致或键盘输入错误;4)可以对C语法做小的修改;5)对类型重命名;6)控制条件编译(#define DEBUG 会将程序在“调试模式”下进行编译);
7、带参数宏,格式: #define 标识符(a,b,c,...) 替换列表
宏的名字和左括号之间必须没有空格。
带参数宏常用来作为简单的函数使用;
带参数的宏可以包含空的参数列表;
8、使用带参数宏替代真正的函数的优点:
程序可能会稍微快一点;宏更通用,使用范围更广;
缺点:
宏参数没有类型检查;无法用一个指针来指向一个宏;宏可能会不止一次地计算它的参数(所以应尽量避免使用带有自增等副作用的参数)
9、宏的替换列表可以包含对其他宏的调用;宏的作用范围通常到出现这个宏的文件末尾,因为宏不受函数作用域的影响;宏不可以被定义两遍,可以用#undef指令来取消对一个宏的定义(如果取消一个没有被定义的宏则不会有任何效果,也不会报错);
10、对于较长的宏可以是使它们包含在一个圆括号内,表达式之间用逗号分隔;或者使它们包含在一个花括号内,语句间用分号分隔,即一个复合语句,且最好使用do...while循环,while条件为0,且最后不要加分号“;”。
11、#号还有一个作用就是使后边的记号转换为字符串,如果包含/号和"号等时会在转换成字符串时自动添加转义字符;
12、##运算符的作用是把两个记号“粘合”在一起,使它们成为一个记号; 如果一个操作数是宏参数,“粘合”会在形式参数被相应的实际参数被替换后发生;
13、C语言预定义宏:
__LINE__ 被编译的文件中的行号;
__FILE__ 被编译的文件名;
__DATE__ 编译的日期(格式为:mm dd yyyy)
__TIME__ 编译的时间(格式为:hh:mm:ss)
__STDC__ 如果编译器符合C标准,那么值为1
14、条件编译 #if...#endif
逻辑同if,效果是如果条件成立则之间的代码会被编译进程序,如果不成立则不会被编译进程序;常用于调试与非调试代码的区别,还有就是不同平台之间代码的区别; 还可以用于临时屏蔽包含注释的代码;
15、defined(标识符) 用于判断一个标识符是否是一个定义过的宏,如果是则返回1,否则返回0
16、#ifdef...#endif 同 #if defined(标识符)...#endif
17、#ifndef...#enif 同 #if !defined(标识符)...#endif
18、#error 常和#if...#endif一起使用,用于向编译器抛出错误;
19、#line 用于改变程序行编号方式,可指定从n号后增加,也可来源一个文件的编号方式;
20、宏可以被递归调用,但是不会无限递归,只会调用一次后就停止调用了;


其他补充:
共享变量,可以在头文件对变量进行声明和定义,在其他文件中用extern type name的方式进行声明,这样编译器不会在编译这些文件时为变量分配额外的内存空间;但是同一个变量的声明出现在不同文件中时,编译器无法检查声明是否和变量定义相匹配。

 

posted @ 2021-05-24 15:21  覆手为云p  阅读(848)  评论(0编辑  收藏  举报
停止精灵球