第一章 C语言基础知识
1.基础
一个C语言程序有且只有一个main函数,是程序运行的起点。每个C语言程序写完后,都是先编译(.c),后链接(.obj),最后运行(.exe)。注意的是:.c和.obj文件是无法运行的,只有.exe文件才可以运行。
2.标识符概念
标识符是由字母、数字和下划线组成,并且第一个必须为数字或下划线。标识符分为关键字、预定义标识符和用户标识符。
关键字:不可以作为用户标识符号。注意:If是可以做为用户标识符;因为If中的第一个字母大写了,所以不是关键字。
预定义标识符:可以做为用户标识符,例如:define, scanf, printf, include。
用户标识符:用户在写代码时自己命名的合法标识符。
注意:C语言严格区分大小写,尽量采用能说明程序对象意义的标识符。
关键字列表:
*auto double int struct break else long switch
*case enum register typedef char extern return union
*const float short unsigned continue for signed void
*default goto sizeof volatile do if while static
3.进制转换
(1)C语言只有八、十、十六进制,没有二进制;但在运行时候,所有的进制都要转换成二进制补码来进行处理(详细了解参考计算机组成原理)。八进制规定要以0开头、没有8,逢8进1;如:018的数值是非法的;十六进制规定要以0x开头,A代表10,B代表11,以此类推F代表15。
(2)小数的合法写法:C语言小数点两边有一个是零的话,可以不用写。
如:1.0可写成1. 0.1可写成.1
(3)实型数据的合法形式:
1)、2.333e-1 就是合法的,且数据是2.333×10-1。
2)、e前e后必有数,e后必为整数。
(4) 整型一般是4个字节,字符型是1个字节,双精度型一般是8个字节
int:整型(4字节);char:字符型(1字节);double: 双精度型(8字节);float:浮点型(4字节)。
4.算数表达式和赋值表达式
(1)算数表达式:+, -, *, /, %
两边都是整型的话,结果就是一个整型。3/2的结果就是1,两个整数相除会舍去小数部分。
“/”如果有一边是小数,那么结果就是小数。3/2.0的结果就是1.5。
“%” 符号请一定要注意是余数,%符号两边要求是整数。
(2)复制表达式
表达式数值是最右边的数值,a=b=5;该表达式为5,常量不可以赋值.
int x=y=1;【错,定义时,不可以连续赋值】
int x, y;
x=y=1;【 定义完成后,可以连续赋值】
赋值的左边只能是一个变量.
int x=7.9;【对,x就是7】
float y=7;【对,y就是7.0】
(3)复合的赋值表达式
int a=2;
a*=2+3;运行完成后,a的值是10,相当于a=a*(2+3);
算术运算符与“=”结合在一起,形成复合的赋值运算符。
i+=2 等价于 i=i+2
a % = 3 等价于 a= a%3
a*=b+5 等价子a=a*(b+ 5)
(4)自加表达式
自加、自减表达式:假设a=5,++a(是为6),a++(为5);
运行的机理:
1) ++a 是先把变量的数值加上1,然后把得到的数值放到变量a中,然后再用这个++a表达式的数值为6;
2)a++是先用该表达式的数值为5,然后再把a的数值加上1为6,再放到变量a中。
进行了++a和a++后 在下面的程序中再用到a的话都是变量a中的6了。+在前先加后用,+在后先用后加。
(5)逗号表达式
优先级别最低。表达式的数值是逗号最右边的那个表达式的数值.
如:(2, 3, 4)的表达式的数值就是4;
z= (2, 3, 4)(整个是赋值表达式)这个时候z的值为4;
z=2, 3,4(整个是逗号表达式)这个时候z的值 2。
x = (a = 3, 6*a) a = 3 x = 18
x = (a = 3 * 5, a * 4) 表达式值为30, x = 60
运算次序:将3*5的结果15赋值给变量a,再计算括号内第二个表达式的值,结果为60,
60是运算至此括号所构成表达式的值,此时a的值仍为15,最后计算整个表达式的值为30
(6)类型转换
-
隐式类型转换:隐式类型转换是在表达式中自动发生的,无需进行任何明确的指令或函数调用。它通常是将一种较小的类型自动转换为较大的类型,例如,将int类型转换为long类型或float类型转换为double类型。隐式类型转换也可能会导致数据精度丢失或数据截断。
-
显式类型转换:显式类型转换需要使用强制类型转换运算符(type casting operator),它可以将一个数据类型的值强制转换为另一种数据类型的值。强制类型转换可以使程序员在必要时对数据类型进行更精确的控制,但也可能会导致数据丢失或截断。
5.字符
(1)字符数据的合法形式
’1’是字符占一个字节,“1”是字符串占两个字节(含有一个结束符号)。
'0'的ASCII数值表示为48,’a’ 的ASCII数值是97,’A’的ASCII数值是65。
一般考试表示单个字符错误的形式:’65’ ”1”
字符是可以进行算术运算的,记住:’0’- 0=48
大写字母和小写字母转换的方法:'A'+32='a'相互之间一般是相差32。
(2)转义字符
转义字符分为一般转义字符、八进制转义字符、十六进制转义字符
1)一般转义字符:背诵\t、\n、\’、\”、 \\;
2)八进制转义字符:'\141’是合法的,前导的0是不能写的;
3)十六进制转义字符:八x6d’才是合法的,前导的0不能写,并且x是小写。
常用转义字符及其应用:
字符形式 | 含义 | ASCII码 | |
\n | 换行 | 10 | |
\t | 水平制表(下一个Tab) | 9 | |
\b | 退格 | 8 | |
\r | 回车 | 13 | |
\f | 换页 | 12 | |
\\ | 反斜杠\ | 92 | |
\’ | 单引号(撇) | 39 | |
\" | 双引号 | 34 | |
\ddd | 1到3位八进制代表的字符 | ||
\xhhh | 1到2位十六进制代表的字符 |
(3)字符型和整数是近亲:两个具有很大的相似之处
char a = 65 ;
printf(“%c”,a):得到的输出结果:A
printf(“%d”,a);得到的输出结果:65
第二章 输入输出函数
1.数据输出printf()
(1)使用printf和scanf 函数时,要在最前面加上#include<stdio.h>
(2)printf可以只有一个参数,也可以有两个参数。(选择题)
(3)printf(“第一部分”,第二部分 );把第二部分的变量、表达式、常量以第一部分的形式展现出来!
(4)printf (“a=%d,b=%d”,12,34)重点!一定要记住是将12和34以第一部分的形式现在在终端也就是黑色的屏幕上。在黑色屏幕上面显示为 a=12,b=34
printf (“a-%d,\n b-%d”,12,34)那么输出的结果就是: a=12,
b = 34
(5)int x=017; 一定要弄清楚为什么是这个结果!过程很重要
printf(“%d”, x); 15 十进制
printf(“%o”, x); 17 八进制
printf(“%#o”, x); 017 带前导的八进制
printf(“%x”, x); f 十六进制
printf(“%#x”, x);0xf 带前导的十六进制
常用printf转换描述
格式说明 | 表示内容 | 格式说明 | 表示内容 | ||
%d | 整型int | %c | 字符 char | ||
%ld | 长整型 long int | %s | 字符串 | ||
%f | 浮点型 float | %o | 八进制 | ||
%If | double | %#o | 带前导的八进制 | ||
%% | 输出一个百分号 | %x | 十六进制 | ||
%5d | %#X | 带前导的十六进制 | |||
转换描述 | 对应参数类型 | 实现的转换 | |||
%md | int | 输出十进制整数,m为输出最小宽度 (如数据的位数小于m,则左端补空;若数据位数大于m,则按实际长度输出) | |||
%m.nf | float,double | 按带小数形式输出实数,m为输出最小宽度,n为小数点后位数。 (如数据的位数小于m,则左端补空;若数据位数大于m,按实际长度输出。小数位数被截断时按四舍五入输出) |
(6)int x = 12, y = 34;
char z = ‘ a ’;
printf(“%d”, x, y);一个格式说明,两个输出变量,后面的y不输出
printf(“%c”, z);
输出结果为:12a
printf(“%2d”,123);第二部分有三位,大于指定的两位,原样输出123
printf (“%5d”,123);第二部分有三位,小于指定的五位,左边补两个空格 123
printf(“%10.6f”,1.25);小数要求补足6位的,没有六位的补0,。结果为 1.250000
printf(“%5.3f”,1.25);小数三位,整个五位,结果为1.250(小数点算一位)
printf(“%3.1f”,1.25);小数一位,整个三位,结果为1.3(要进行四舍五入)
2.数据输入scanf()
(1)scanf(“a=%d,b=%d”,&a,&b)考试超级重点!
一定要记住是以第一部分的格式在终端输入数据。
在黑色屏幕上面输入的为a=12,b=34才可以把12和34正确给a和b。有一点不同也不行。
(2)scanf(“%d,%d”,x,y);这种写法绝对错误,scanf的第二个部分一定要是地址!
scanf (“%d,%d”,&x,&y);注意写成这样才可以!
(3)特别注意指针在scanf的考察例如:
int x=2; int *p;
p=&x;
scanf (“%d”,x);错误scanf (“%d”,&p);错误
scanf(“%d”,p);正确scanf(“%d”,*p)错误
(4)指定输入的长度(考试重点)
终端输入:1234567
scanf (“%2d%4d%d”,&x,&y,&z);x为12,y为3456,z为7
终端输入:1 234567
由于1和2中间有空格,所以只有1位给x
scanf(“%2d%4d%d”,&x,&y,&z);x为1,y为2345,z为67
(5)字符和整型是近亲:
int x=97;
printf (“%d”,x);
printf ( "%c" , x) ;
结果为97
(6)输入时候字符和整数的区别(考试超级重点)
scanf(“%d”,&x);这个时候输入1,特别注意表示的是整数1
scanf(“%c”,&x);这个时候输入1,特别注意表示的是字符“1’ ASCII为整数49。
补充:
1) putchar , getchar 函数的考査:
char a = getchar()是没有参数的,从键盘得到你输入的一个字符给变量a。
putchar(‘y’)把字符y输出到屏幕中。
2)如何实现两个变量x,y中数值的互换(要求背下来)不可以把 x=y,y=x;要用中间变量 t = x;
x = y;
y = t;
第三章 表达式和数据结构
1.表达式
(1)关系表达式
a、关系表达式的数值只能为1(表示为真),或O(表示假)
如 9>8这个关系表达式是真的,所以9>8这个表达式的数值就是1
如 7<6这个关系表达式是假的,所以7<6这个表达式的数值就是0
b、考试最容易错的:就是int x=1,y=0,z=2;
x < y < z是真还是假?带入为1<0<2,从数学的角度出发肯定是错的,但是如果是C语言 那么就是正确的!因为要1<0为假得到0,表达式就变成了0<2那么运算结果就是1
c、等号和赋值的区别!一定记住“=”就是赋值,“==”才是等号
(2)逻辑表达式
核心:表达式的数值只能为1(表示为真),或0(表示假)。
a) 共有&& , || , !三种逻辑运算符号。
b)!> && > || 优先的级别。
c) 表示x 大于0小于10的方法。 0<x<10是不行的(一定记住)。是先计算0<x得到的结果为1 或则0;再用0,或1与10比较得到的总是真(为1)。所以一定要用1(0<x)&&(x<10) 表示比0大比10小。
2.数据结构
(1)if语句
a)else 是与最接近的if且没有else的语句匹配。
b)交換的程序写法:t=x;x = y; y=t;
if (a < b) {t=a;a=b;b=t;}
c)单独的if语句:if(a < b)t=a;
标准的if语句:if(a < b)min=a;
else min=b;
嵌套的if语句:if (a < b)
if (b > c) printf ( "ok!" );
多选一的if语句 if (a == t)printf(“a”):
else if (b == t) printf ("b" );
else if (c == t) printf ("c" );
else pritnf("d" );
(2)条件表达式
表达式1 ?表达式2:表达式3
考试口诀:真前假后。
注意是当表达式1的数值是非0时,才采用表达式2的数值做为整个运算结果,当表达式1的数 值为0时,就用表达式3的数值做为整个的结果。 c、int a=l, b=2, c=3,d=4,e=5;
int a = 1, b = 2,c = 3, d = 4, e = 5;
k = a < b ? c : d; 求k的数值是多少? 答案为3 。
k = d > e ? d : e; 求k的数值是多少? 答案为5。
(3)switch语句
a)执行的流程一定要弄懂!
b) 注意有break 和没有break的差别
没有break时候,只要有一个case匹配了,剩下的都要执行,有break则是直接跳出switch语 句。
c) switch只可以和break一起用,不可以和continue用。
d) switch (x) x:是整型常量,字符型常量,枚举型数据,不可以是变量。
{case 1: ···
case 2:⋯.}
(4)循环结构
1)三种循环结构:
a) for(;;) ;while(); do- while()三种。
b) for循环当中必须是两个分号,千万不要忘记。
c)写程序的时候一定要注意,循环一定要有结束的条件,否则成了死循环。
d)do-while()循环的最后一个while();的分号一定不能够丟,do-while循环是至少 执行一次循环。
2)break 和 continue
break:是打破的意思,(破了整个循环)所以看见break就退出整个一层循环。
continue: 是继续的意思,(继续循环运算),但是要结束本次循环,就是循环体内剩下的 语句不再执行,跳到循环开始,然后判断循环条件,进行新一轮的循环。
第四章 函数
- 函数:是具有一定功能的一个程序块,是C语言的基本组成单位。
- 函数的定义:[函数类型]函数名(形式参数)函数不可以嵌套定义。但是可以嵌套调用。
- 函数名缺省返回值类型,默认为 int。
- C语言由函数组成,但有且仅有一个main函数!是程序运行的开始!
- 判断质数:
#include <stdio.h> int main(){ int i,n; printf("Please input: "); scanf("%d",&n); for(i=2;i<=n-1;i++){ if(n%i==0){ break; } } if(i>=n){ printf("This is a prime!\n"); }else{ printf("This is not a prime!\n"); } return 0; }
6.求n的阶层:
void func(int n){ int p = 1; for (int i = 1; i <= n i++) { p = p * i; } return p; }
7.函数的参数可以是常量、变量、表达式和函数调用:
add(int x, int y) { return x + y; } main() { int sum; sum = add(add(3, 4), 9);//sum的结果为24 }
8.函数的参数,返回值
int add(int x, int y) {//x, y 是形式参数,int是函数的返回值类型 int z; z = x + y; return z;//z就是这个add函数计算后得到的结果,就是函数返回给主程序的返回数值。 } int main() { int a = 5, b = 6, c;// a, b 是实参 c = add(a, b); //函数调用 printf("%d", c);//整个函数得到一个数值就是函数的返回值 }
程序是在从上往下顺序执行,当碰到了函数add后,把a,b的数值穿给调用函数,程序暂时中断等待返回数值。当得到了返回数值后,再顺序的往下执行。
9.注意参数之间的传递
实参和形参之间 传数值,和传地址的差别。(考试的重点)传数值的话,形参的变化不会改 变实参的变化。传地址的话,形参的变化就会有可能改变实参的变化(学完指针再来看)。
exch1(int x, int y) {
int t;
t = x;
x = y;
y = t;
}
exch2(int *x, int *y) {
int t = *x;//定义中间变量 然后交换两个数
*x = *y;
*y = t;
}
void main() {
int a1 = 2, b1 = 5;
int a2 = 2, b2 = 5;
exch1(a, b);
printf("a1 = %d, b1 = %d\n", a, b);
exch2(&a2, &b2);
printf("a2 = %d, b2 = %d\n", a, b);
}
输出结果为a1 = 2, b1 = 5;a2 = 5, b2 = 2;exch1没有交换成功。
10.常见的库函数
(1)库函数是已经写好了函数,放在仓库中,我们只需要如何去使用就可以了!
(2)以下这些库函数经常考到,所以要背诵下来。
abs()、sqrt()、fabs()、pow()、sin(), 其中pow(a,b)2是指a的b次方。
第五章 指针
指针变量的本质是用来放地址,而一般的变量是放数值的。
1.指针的定义(两种形式)
1) int x=3: int *p=&x
2)int x; int *p;
x = 3;p = &x
int *p中*p和p的差别:简单说*p是数值,p是地址!
*p可以当做变量来用;*的作用是取后面地址p里面的数值
P是当作地址来使用。可以用在scanf函数中:scanf(“%d”,p);
2.*p++和(*p)++的之间的差别
改错题目中很重要!考试超级重点
*p++是 地址会变化。口诀:取当前值,然后再移动地址!
(*p)++是数值会要变化。口诀:取当前值,然后再使数值增加1。
例题:
int *p, a[] = {1, 3, 5, 7, 9};
p = a;
请问*p++ 和 (*p)++的值分别为多少?
- *p++: 这个本身的数值为1。由于是地址会增加一,所以指针指向数值3了。
- (*p)++这个本身的数值为1。由于有个++表示数值会增加,指针不移动,但数值1由于自加 了一次变成了2。
-
3.二级指针
- *p:一级指针:存放变量的地址
- **p:二级指针:存放一级指针的地址
- 例题:
-
int x = 7; int *p = &x, **q = p;
问:请问*p为多少?*q为多少?**p为多少?
-
*p为7;*q为p;**q为7
-
-
- *p:一级指针:存放变量的地址
4.三名主义
数组名:表示第一个元素的地址。数组名不可以自加,他是地址常量名。
函数名:表示该函数的入口地址。
字符串常量名:表示第一个字符的地址。
5.移动指针
char *s = "qiuguanzhu";
while(*s) {
printf("%c", *s);
s++;
}
这个s首先会指向第一个字母m然后通过循环会一次打印出一个字符,st+是地址移动,打印了一个字母后,就会移动到下一个字母!
6.指针变量两种初始化
方法一:int a = 2, *p = &a; (定义的同时初始化)
方法二:int a = 2, *p; (定义之后初始化)
p = &a;
7.函数的返回值是地址
int *func(int *a, int *b) {//函数前面加了*,所以运算结果是地址
if (*a > *b) {
return a;
} else {
return b;
}
}
main() {
int x = 7, y = 8, *max;
max = func(&x, &y);
printf("%d", max);
}
第六章 数组
数组:存放的类型是一致的, 多个数组元素的地址是连续的。
(1)一维数组的初始化:
int a[5] = {1, 2, 3, 4, 5}; 合法
int a[5] = {1, 2, 3, }; 合法
int a[] = {1, 2, 3, 4, 5}; 合法
int a[5] = {1, 2, 3, 4, 5, 6} ;不合法,赋值个数多于数组的个数
一维数组的重要概念:
对a[10]这个数组的讨论。
1、a表示数组名,是第一个元素的地址,也就是元素a[0]的地址。(等价于&a)
2、a是地址常量,所以只要出现a++,或者是a=a+2赋值的都是错误的。
3、a是一维数组名,所以它是列指针,也就是说a+1是跳一列。
(2)一维数组的定义
int a[5];注意这个地方有一个重要考点,定义时数组的个数不是变量一定是常量。
int a [5] 合法,最正常的数组
int a[1+1] 合法,个数是常量2,是个算术表达式
int a[1/2+4] 合法,同样是算术表达式
int x=5, int a[x]; 不合法,因为个数是x,是个变量,非法的,
define P 5 int a[P]; 合法,define 后的P是符号常量。
(3)二维数组的初始化
int a [2] [3]=(1, 2, 3, 4, 5, 6} ; 合法,很标准的二维的赋值。
int a [2] [3]=(1, 2, 3, 4, 5, }; 合法,后面一个默认为0。
int a[2] [3]= ({1, 2, 3, } {4, 5, 6} } ; 合法,每行三个。
int a[2][3]=({1, 2, } (3, 4, 5}} : 合法,第一行最后一个默认为0。
int al2][3]=(1, 2, 3, 4, 5, 6, 7} ; 不合法,赋值的个数多余数组的个数了
int a[ ][3] = (1, 2, 3, 4, 5, 6} ; 不合法,不可以缺省行的个数。
int a[2] [ ]={1, 2, 3, 4, 5, 6} ; 合法,可以缺省列的个数。
对于a[3][3]的讨论:
1、a表示数组名,是第一个元素的地址,也就是元素a[0][0]的地址。
2、a是地址常量,所以只要出现a++,或者是a=a+2赋值的都是错误的。
3、a是二维数组名,所以它是行指针,也就是说a+1是跳一行。
4、a[0]、a[1]、a[2]也都是地址常量,不可以对它进行赋值操作,同时它们都是列指针,a [0]+1,a[1]+1,a[2]+1都是跳一列。
5、注意a和alo]、a[1]、a[2]是不同的,它们的基类型是不同的。前者是一行元素,后 三者是一列元素。
第七章 其他
(1)字符串
strlen()字符串测长函数
strcat()字符串连接函数
strcmp()字符串比较函数
strepy()字符串拷贝函数
(2) strlen ()和 sizeof()的区别
①sizeof是一个操作符,strlen是库函数。
②sizeof的参数可以是数据的类型,也可以是变量,而strlen只能以结尾为“\0‘的字符串 作参数。
③sizeof计算的是数据类型占内存的大小,而strlen计算的是字符串实际的长度。
(3)malloc
int *p;
p = (int *) malloc(4);
p = (int *) malloc(sizeof(int));
以上两个等价,malloc的返回值类型是void *
(4)两种重要的数组长度
char a[ ] = {‘a’, ‘b’, ‘c’};数组长度为3,字符串长度不定,sizeof(a)为3.
char a[5] = {‘a’, ‘b’, ‘c’};数组长度为5,字符串长度为3,sizeof(a)为5.
(5)scanf和gets
如果输入的是hello hello world
那么scanf(“%s”,a):只会接收 hello
gets(a);会接收hello hello world
(6)结构体
C 数组允许定义可存储相同类型数据项的变量,结构是 C 编程中另一种用户自定义的可用的 数据类型,它允许您存储不同类型的数据项。
结构体中的数据成员可以是基本数据类型(如 int、float、char 等),也可以是其他结构体类 型、指针类型等。
定义结构体
结构体定义由关键字 struct 和结构体名组成,结构体名可以根据需要自行定义。
struct 语句定义了一个包含多个成员的新的数据类型,struct 语句的格式如下:
struct tag {
member-list
member-list
member-list
...
} variable-list ;