C语言基础学习笔记.docx
《C语言基础学习笔记.docx》由会员分享,可在线阅读,更多相关《C语言基础学习笔记.docx(40页珍藏版)》请在冰豆网上搜索。
![C语言基础学习笔记.docx](https://file1.bdocx.com/fileroot1/2022-11/16/ba97c56a-289a-4552-b24b-c7e421c0aea5/ba97c56a-289a-4552-b24b-c7e421c0aea51.gif)
C语言基础学习笔记
C语言基础学习笔记
(第一版修改)
丁炳亮
1数据类型和表达式
1.1计算机内数据存储方式
理解与测试:
计算机内部所有的数据都是以二进制的形式存储的。
我们平常使用的有理数都是分正负数的,在计算机内部整型是通过最高位区分正负数,负数的最高位为1。
如果直接用这种表达方式进行运算,那么运算前要先判断是无符号数还是有符号数,因为有符号数的最高位是符号位不能直接参与运晕,并且减法运算还得有专门的减法器。
为了能把符号位参与运算且加法和减法能够统一处理我们用到了补码。
什么是补码?
我们得先知道模的概念。
模“模”是指一个计量系统的计数范围。
如时钟等。
计算机也可以看成一个计量机器,它也有一个计量范围,即都存在一个“模”。
例如:
时钟的计量范围是0~11,模=12。
表示n位的计算机计量范围是0~2^(n)-1,模=2^(n)。
“模”实质上是计量器产生“溢出”的量,它的值在计量器上表示不出来,计量器上只能表示出模的余数。
任何有模的计量器,均可化减法为加法运算。
例如:
假设当前时针指向10点,而准确时间是6点,调整时间可有以下两种拨法:
一种是倒拨4小时,即:
10-4=6;另一种是顺拨8小时:
10+8=12+6=6在以12模的系统中,加8和减4效果是一样的,因此凡是减4运算,都可以用加8来代替。
对“模”而言,8和4互为补数。
实际上以12模的系统中,11和1,10和2,9和3,7和5,6和6都有这个特性。
共同的特点是两者相加等于模。
二进制中整数的补码求法是:
正数的补码为原码,负数的补码是符号位不变其他位全部取反再整个数加1。
我们可以通过下面的代码看下负整数在计算机内部的表示。
voidf(intn)
{
unsignedinti;
for(i=1,i<<=15;i;i>>=1)
{
if(i&n)
printf("1");
else
printf("0");
}
printf("\n");
}
main()
{
inta=-0xff;
f(a);
getch();
}
输出的结果是1111111100000001。
1.2变量与常量
理解与测试:
1)类型声明
在计算机内部数据是以字节为单位存储的,但是我们需要的数据类型有很多种,每种数据类型所占字节和存储方式都不一样。
类型声明的作用就是告诉计算机以哪种“格式”去读写该数据数据。
类型说明符变量名1,变量名2......,变量名n;
类型说明符有基本类型(字符型、整数型、单/双精度型)、高级类型(结构体型、共用体型、枚举类型)、指针型等,其中指针类型包括指向基本类型的指针类型、指向高级类型的指针型和指向函数的指针类型(指向函数指针声明格式在后面章节)。
2)符号常量的定义
#define标识符常量;
使用该种方法定义符号常量一个是可以使代码便于阅读理解,另一个是方便代码内部多个相同常量的统一修改。
总结与注意
在写计算式的时候要考虑变量是否会越界。
一般来说计算式子时是先强制转换成式子中最大存储空间的数据类型(不包括被赋值的变量),还要注意不同的类型数据在不同的编译器中所占的内存有可能是不一样的,例如有些编译器整型是占2个字节有些是占4个字节。
同时还要考虑到符号的优先级和结合顺序,如果按符号的优先级和结合顺序运算过程中有越界的那么整个计算结果可能和预想的不一样了,例如inti=100;i=500*i/i;最后i=-155。
1.3输出输入
理解与测试:
1)格式化输入输出函数可以按设定的格式和设定的数据类型接收和输出多个变量。
控制格式和数据类型的是数据控制符。
2)字符和字符串可以用专门的输出\输入函数。
主要有getch();putch();getchar();putchar();gets();puts();其中getch()和putch()是conio.h中声明,getch()不需要等待回车键就返回字符并立即执行下面一语句符,getch()不在屏幕显示输入的字符。
getchar();putchar();在stdio.h中声明。
getchar()读取键盘上的一个字符,立即返回并显示在屏幕上,需要等待回车键才能执行下一条语句。
例如下面的代码:
intmain(void)
{
charch,i;
for(i=0;i<10;i++)
{
ch=getchar();
putchar(ch);
}
getch();
}
输入:
ILOVEYOU
输出:
ILOVEYOU
总结与注意
格式输入函数中的参数是变量存放的地址,所以变量前面要”&”符号。
如果是数组则可以直接用数组名,因为数组名就是指向该数组首地址的指针常量。
1.4运算符号
理解与测试:
1)表达式中符号的运算顺序是有先后的,根据符号的优先级和结合性(左结合/右结合)来判定。
如果是几个符号连在一起C内部是怎么去读的呢?
有一个很简单的规则:
每一个符号应该包含尽可能多的字符。
也就是说,编译器读取符号的方法是,从左到右一个字符一个字符地读入,如果该字符可能组成一个符号,那么在读入下一个字符,直到与下个字符组合成的符号没有意义为止。
例如:
a---b;这个表达式等效于(a--)-b;
2)复合赋值符及表达式在赋值符“=”之前加上其他双目运算符号可以构成复合赋值符。
如:
+=、-=、*=、/=、%=。
构成复合赋值表达式的一般格式为
变量双目运算符=表达式
等价于
变量=变量运算符表达式
可以这么去理解,等号左边的相当于变量自增、自减、自除、自取余一个数,这个数由右边的表达式计算得到。
如:
inta=7,b=3,c=3;a+=b+=c+=5;运算后是a=18,b=11,c=8。
3)C中唯一一个三目运算符是条件运算符,由“?
”和“:
”构成。
两个符号必须按下面的格式一起使用:
表达式1?
表达式2:
表达式3
三个表达式可以是任意的合法表达式,条件运算符的运算规则如下:
如果表达式1的值为真,那么整个表达式的值为表达式2的值,否则为表达式3的值。
4)sizeof()也是一个运算符号,它可以对一个数据类型或一个变量取类型长度。
但是当一个数组名作为一个实参传递给函数时,在函数内部是不能用sizeof来获取该数组的长度的。
因为数组名是一个指向数组首地址的指针,使用sizeof只能取得实参指针类型长度。
5)比较少用到的符号是“:
”和“,”。
冒号运算符在C中有三种用途,第一种是我们上面讲到的与“?
”构成三目运算。
第二种是在switch中放在常量表达式后面。
第三种用法是在结构体中定义位域时用到。
struct位域结构名
{位域列表};
其中位域列表的形式为:
类型说明符位域名:
位域长度
例如:
structbs
{
inta:
8;
intb:
2;
intc:
6;
};
逗号运算符的功能是把两个表达式连在一起组成一个新的表达式,称为逗号表达式。
其一般格式为
表达式1,表达式2,表达式3,...,表达式n;
其求值过程是自左向右求两个表达式的值,并以最后一个表达式的值作为整个逗号表达式的值。
例如for(a=0,b=0,c=0;b<10,a<20;b++,a++)++c;运算后c=20,如果把中间的两个语句前后调换for(a=0,b=0,c=0;b<10,a<20;b++,a++)++c;运算后c=10。
6)不同的数据类型的量混合运算的时候,系统会临时把算式中长度小的数据类型自动转换成长度大的数据类型。
在某些时候我们需要临时改变一个数据的类型或者说是读取“格式”,我们可以使用强制类型转换符,”(type)”。
使用的格式一般如下:
(类型说明符)表达式
要得到一个数据类型的类型说明符很容易。
只要知道如果声明一个给定类型的变量,那么就可以得到该数据类型的转换符就是把声明中变量名和声明的分号去掉。
例如:
(int)、(float)、(char*)、(int(*)())等等。
总结与注意
1)“==”和“=”这两个符号也容易在判断语句内出错,严重的还会出现死循环。
2)自增“++”和自减“--”可以作为前缀也可以作为后缀。
作为变量前缀时,在表达式中每次取用变量值运算前先自增/自减,作为变量后缀时,在表达式中每次取用变量值运算后再自增/自减。
例如:
main()
{
inti=2,j=1,n;
printf("%d\n",i++);
n=i++>j?
i++:
j;
printf("%d\n",n);
getch();
}
输出结果:
2
4
3)在写式子时要注意运算符号对变量的副作用,单目运算有“++”和“--”,双目运算有“=”。
4)位运算符号与逻辑符号容易混淆的有“&”和“&&”、“|”和“||”、“~”和“!
”。
前面两个可以这么记,位运算是单个的所以符号也是单个的。
5)在使用位运算符号时要主要如果是有符号数则是对他们的补码执行位运算。
对于有符号的整数型使用左移“<<”右补0,使用右移“>>”左补1。
如下代码:
voidf(intn)
{
unsignedinti;
for(i=1,i<<=15;i;i>>=1)
{
if(i&n)
printf("1");
else
printf("0");
}
printf("\n");
}
main()
{
inta=-0xff;
f(a);
a>>=1;
f(a);
getch();
}
输出的结果是:
1111111100000001
1111111110000000
6)运算符优先级可以简单归纳如下几点:
①单目运算符比任何一个真正意义上的运算符的优先级高。
②逻辑运算符比关系运算符优先级高。
③移位运算符表算术运算符优先级低,但高于关系运算符。
2程序控制结构
2.1选择结构
理解与测试:
使用if-else多层嵌套时else是与上面同一层的最近if相结合的,在程序设计时有过多的分支最好要选择使用if-else,当然如果可以使用switch语句还是尽量选择switch语句或者使用其他能使代码简洁易懂的方法。
如下面的代码:
main()
{
inta=10,b=6,c=7,d=8,e=9,f=10;
if(a>b)
{
printf("%d\n",a);
if(b>c)
{
printf("%d\n",b);
if(c>d)
{
printf("%d\n",c);
if(d>e)
{
printf("%d\n",d);
if(e>f)
{
printf("%d\n",e);
}
else
printf("%d\n",f);
}
}
}
}
getch();
}
这种代码又长又难看懂,更要命的是经常搞不懂下面的大括号对应上面的哪个大括号。
改进后的代码如下
main()
{
inta=10,b=6,c=7,d=8,e=9,f=10;
while
(1)
{
if(a<=b)break;
printf("%d\n",a);
if(b<=c)break;
printf("%d\n",b);
if(c<=d)break;
printf("%d\n",c);
if(d<=e)break;
printf("%d\n",d);
if(e<=f)
printf("%d\n",e);
else
printf("%d\n",f);
break;
}
getch();
}
第二种方法比第一种方法来看上去更干净,理解上差不了多少。
2)
总结与注意
switch语句中每一个分支结束都要有break;语句,如果