C语言程序基础知识
1.双精度浮点型数据用%lf输出。因为double是8个字节的,float是4个字节的,%f 的格式就是4个字节的,而 %lf 就是8个字节的。 例如:printf("%lf\n",x);
2.short 占用内存空间2个字节,短整型数据用%d输出 例如:printf("%d\n",a);
进制
二进制
二进制由 0 和 1 两个数字组成,使用时必须以 0b 或 0B(不区分大小写)开头,
八进制
八进制由 0~7 八个数字组成,使用时必须以 0 开头(注意是数字 0,不是字母 o)
十六进制
十六进制由数字0-9,字母A~F或 a~f(不区分大小写)组成,使用时必须以 0x 或 0X(不区分大小写)开头。
C 语言中常用的整数有 short、int 和 long 三种类型,通过 printf 函数,可以将它们以八进制、十进制和十六进制的形式输出。
下表列出了不同类型的整数、以不同进制的形式输出时对应的格式控制符:
short |
int
|
long
| |
八进制
|
%ho
|
%o
|
%lo
|
十进制
|
%hd
|
%d (红色部分重点记忆)
|
%ld
|
十六进制
|
%hx或%hX
|
%x或%X
|
%lx或%lX
|
选择结构的嵌套
在 if 语句中又包含一个或多个 if 语句称为 if 语句的嵌套。其一般形式为:
if(表达式)
if(表达式) 语句1;
else 语句2;
else if(表达式) 语句3;
else 语句4;
逻辑运算符和逻辑表达式
C 语言中有3种逻辑运算符,如下表:
运算符
|
含义
|
举例
|
说明
|
&&
|
逻辑与
|
a&&b
|
如果 a 和 b 都为真,则结果为真,否则为假。
|
||
|
逻辑或
|
a || b
|
如果 a 和 b 有一个以上为真,则结果为真;二者都为假时,结果为假。
|
!
|
逻辑非
|
!a
|
如果 a 为假,则 !a 为真;如果 a 为真,则 !a 为假。
|
if 语句会根据对某个条件的判断结果,将程序的流程分为两支。而本章节将要介绍的 switch 语句,则会将程序分为多个分支。
switch 语句
switch 语句的作用是根据表达式的值,使流程跳转到不同的语句。switch 语句的一般形式如下:
switch(表达式)
{
case 常量1: 语句1;
case 常量2: 语句2;
……
case 常量n: 语句n;
default: 语句n+1;
}
使用时注意下面事项:
-
switch 后面括号内的“表达式”,其值的类型应为 整数类型(包括字符串) 。
-
执行 switch 语句时,先计算 swith 后面的“表达式”的值,然后将它与各 case 标号比较,如果与某一个 case 标号中的常量相同,流程就转到此 case 标号后面的语句。如果没有与 switch 表达式相匹配的 case 常量,流程转去执行 default 标号后面的语句。
-
可以没有 default 标号,此时,如果没有与 switch 表达式相匹配的 case 常量,则不执行任何语句,流程转到 switch 语句的下一个语句。
-
各个 case 语句标号出现次序不影响执行结果。
-
每一个 case 常量必须互不相同,否则就会出现互相矛盾的现象。
数学函数库
C 语言提供了许多的数学函数,要使用这些函数时,在程序文件头必须加入: #include <math.h>或 #include "math.h"
需要注意的是,这些函数已经在math.h或其它标头档宣告过了,因此在使用时不必再加型别宣告。
例如:y=sin(x);不用写成y=double sin(double x);。
abs 函数
abs 函数: 求整型变量 x 的绝对值,返回计算结果为整型。函数原型为:int abs(int x)。
例如:
int a = -5;
printf("%d",abs(b));
输出结果:5
fabs 函数
fabs 函数: 求浮点型变量 x 的绝对值,返回计算结果为浮点型。函数原型为:double fabs(double x)。
例如:
double a = -5.654;
printf("%lf",fabs(a));
输出结果:5.654000
sqrt 函数
sqrt 函数:计算根号 x( x >= 0 ),返回计算结果。函数原型为:double sqrt(double x)。
例如:
double b = 9;
double a = sqrt(b); // 对9求根号
printf("%f",a);
输出结果:3.000000
sin 函数
sin 函数:
计算 SINx 的值(x 单位为弧度),返回计算结果。函数原型为: double sin(double x)。
例如:
double pi =3.1415;
double a = sin(pi);
printf("%f",a);
输出结果:0.000093
gets()函数
1.描述
C 库函数 char *gets(char *str) 从标准输入 stdin 读取一行,并把它存储在 str 所指向的字符串中。当读取到换行符时,或者到达文件末尾时,它会停止,具体视情况而定。
gets(str) 约等于 scanf("%s",&str) 会把读到的字符串写入数组,但又不同。
2.区别
scanf("%s",&str) :读到空格便停止。
gets(str) :一直读到敲回车(不管中间是否有空格)。
(区别2)
这里顺便提一下printf() 和 puts() 的区别
puts()在输出字符串时会将’\0’自动转换成’\n’进行输出,也就是说,puts方法输出完字符串后会自动换行。
最牛逼最难但很重要之指针
定义指针变量
定义指针变量的一般形式为:类型名 * 指针变量名;
例如:int * pointer_1, * pointer_2;
说明:
-
左边的 int 类型是在定义指针变量时必须指定的基类型, 指针变量的基类型用于表示指针变量可以指向的变量的类型;
-
指针变量前面的 * 表示该变量的类型为指针型变量;
-
指针变量名是 pointer_1 和 pointer_2 ,而不是 * pointer_1 和 * pointer_2 。
在引用指针变量时,可以有以下两种情况:
-
给指针变量赋值
例如:
int * p;
int a = 3;
p = &a; // 把 a 的地址赋给指针变量 p
这样,指针变量 p 的值就是变量 a 的地址,也可以说 p 指向 a 。
注意:&为取地址运算符,&a 表示 a 的地址。
-
引用指针变量指向的变量
例如:
-
int * p ;
-
int a = 3 ;
-
p = & a ;
-
printf ( "%d" ,* p );
便可以以整数形式输出指针变量 p 所指向的变量的值,即变量 a 的值 3。
注意:* 为指针运算符,*p 代表指针变量 p 所指向的对象
如有以下赋值语句:* p = 1,表示将整数1赋给指针 p 所指向的变量,相当于a = 1。
指向数组元素的指针
一个指针变量既可以指向变量,也可以指向数组元素(即把某一个元素的地址放到一个指针变量中)。
例如:
-
int a [ 5 ] = { 1 , 3 , 5 , 7 , 9 };
-
int * p ;
-
p = & a [ 0 ];
以上是使指针变量 p 指向 a 数组的第0个元素。
引用数组元素时指针的运算
当指针指向数组元素时,可以对指针进行加和减运算。
如上例子 p 指向数组元素 a[0] , p+1 则表示指向下一个数组元素 a[1] 。
在指针指向数组元素时,可以对指针进行以下运算:
注意:如果指针变量 p 指向数组中的一个元素,则 p+1 指向同一数组中的下一个元素, p-1 指向同一数组中的上一个元素。
-
加一个整数,如 p+1
-
减一个整数,如 p-1
-
自加运算,如 p++ , ++p
-
自减运算,如 p-- , --p
-
两个指针相减,如 p1-p2 (只有当 p1 和 p2 都指向同一个数组中的元素才有意义)
引用数组元素
引用一个数组元素,可以有两种方法:
-
下标法:如 a[i] 的形式。
-
指针法:如 *(a+i) 或 *(p+i) ,其中 a 是数组名, p 是指向数组元素的指针变量,其初值为 p = a 。
说明:因为 p+i 是指向 p 所指元素后第 i 个元素的指针,所以在其前加上指针运算符后得到的*(p+i)就是该元素的别名。因此,如果 p 指向 a[0],那么表达式*(p+i)就表示 a[i] 本身。
0表示整数,'0'表示0字符,'\0'表示ASCII码值为0的字符。
指向函数的指针变量
定义指向函数的指针变量的一般形式为:数据类型 (*指针变量名)(函数参数表列);
例如: int (*p)(int,int);
注意事项:
-
定义指向函数的指针变量,并不意味着这个指针变量可以指向任何函数,它只能指向在定义时指定的类型的函数;
-
如果要用指针调用函数,必须先使指针变量指向该函数;
如:p = max; // max为已定义的函数的函数名
-
在给函数指针变量赋值时,只须给出函数名而不必给出参数;
-
对指向函数的指针变量不能进行算术运算;
-
用函数指针变量调用函数时,只须将 *p 代替函数名即可( p 为指针变量名),在 *p 之后的括号中根据需要写上实参。
如:c = (*p)(a,b);
函数的递归调用
在调用一个函数的过程中又出现直接或间接地调用该函数本身,称为函数的递归调用。
C语言函数的参数会出现在两个地方,分别是函数定义处和函数调用处,这两个地方的参数是有区别的。
形参(形式参数)
在函数定义中出现的参数可以看做是一个占位符,它没有数据,只能等到函数被调用时接收传递进来的数据,所以称为
形式参数
,简称
形参
。
实参(实际参数)
函数被调用时给出的参数包含了实实在在的数据,会被函数内部的代码使用,所以称为
实际参数
,简称
实参
。
形参和实参的功能是传递数据,发生函数调用时,实参的值会传递给形参。
数组作为函数参数
数组可以作为函数的参数使用,进行数据传送。
数组用作函数参数有两种形式,一种是把数组元素(下标变量)作为实参使用;另一种是把数组名作为函数的形参和实参使用。
数组元素作函数参数
数组元素就是下标变量,它与普通变量并无区别。 因此它作为函数实参使用与普通变量是完全相同的,在发生函数调用时,把作为实参的数组元素的值传送给形参,实现单向的值传送。
数组名作为函数参数
用数组名作函数参数与用数组元素作实参有几点不同:
-
数组元素(下标变量)作为实参
-
形参数组和实参数组类型必须一致,否则出错;
-
在函数形参表中,允许不给出形参数组的长度,或用一个变量来表示数组元素的个数;
-
形参数组和实参数组长度可以不相同,因为在调用时,只传递首地址而不检查形参数组的长度。★
-
数组名作为函数参数
-
用数组元素作函数参数不要求形参也必须是数组,但是用数组名作函数参数时,则要求形参和相对应的实参都是类型相同的数组;
-
在 C 语言中,数组名除作为变量的标识符之外,数组名还代表了该数组在内存中的起始地址,当数组名作函数参数时,实参与形参之间不是“值传递”,而是“地址传递”,实参数组名将该数组的真实地址传给形参数组,两个数组共享一段内存单元,编译系统不再为形参数组分配存储单元;//★ 数组名作形参(无[]),为直接导入数组内全部元素
-
在变量做函数参数时,所进行的值传递是单向的。即只能从实参传向形参,不能从形参传回实参。
字符串函数的使用
在使用字符串函数前必须使用以下命令包含头文件:#include <string.h>
用来求字符串长度的 strlen 函数。
例如:
char str[]="hello";
int l = strlen(str);
printf("%d",l);
输出结果为:5
数组
一维数组
在程序中可以使用下标变量,即说明这些变量的整体为数组,数组中的每个变量的数据类型是相同的。当数组中每个元素都只带有一个下标时,称这样的数组为一维数组。
定义一维数组的一般形式为:
-
类型名 数组名[常量表达式];
例如,下面是定义一个整型数组,数组名为 a ,此数组有10个整型元素:
-
int a [ 10 ];
定义数组需遵循的规则:
-
数组名的命名规则和变量名相同,遵循标识符命名规则。
-
在定义数组时,需要指定数组中元素的个数,方括号中的常量表达式用来表示元素的个数,即数组长度。
例如上例中,指定 a[10] ,表示 a 数组有10个元素。注意,下标是从0开始的,这10个元素是 a[0]~a[9] ,请特别注意,按上面的定义,不存在数组元素 a[10] 。
-
常量表达式中可以包括常量和符号常量。如 int a[3+5]; 是合法的,但不能包含变量,如 int a[n] 是不合法的。
定义数组需遵循的规则:
-
数组名的命名规则和变量名相同,遵循标识符命名规则。
-
在定义数组时,需要指定数组中元素的个数,方括号中的常量表达式用来表示元素的个数,即数组长度。
例如上例中,指定 a[10] ,表示 a 数组有10个元素。注意,下标是从0开始的,这10个元素是 a[0]~a[9] ,请特别注意,按上面的定义,不存在数组元素 a[10] 。
-
常量表达式中可以包括常量和符号常量。如 int a[3+5]; 是合法的,但不能包含变量,如 int a[n] 是不合法的。
一维数组的初始化
数组的初始化方法有很多,现介绍最常见的两种:
-
在定义数组时对全部数组元素赋予初值
例如:int a[10] = {0,1,2,3,4,5,6,7,8,9};
将数组中各元素的初值顺序放在一对花括号内,数据间用逗号隔开。花括号内的数据就称为初始化列表。经过上面的定义和初始化之后,a[0]=0,a[1]=1,……,a[9]=9。
-
通过循环语句对数组元素赋予初值
int a[10]; int i; for(i=0;i<10;i++) scanf("%d",&a[i]);
这种方式的值则是通过键盘输入的值来确定,因此较灵活。
二维数组
上一关中所学习的数组,其元素都是 int 型或 double 型等单一类型。实际上,数组的元素也可以是数组本身。
以数组作为元素的数组是二维数组,以二维数组为元素的数组是三维数组。当然也可以生成维数更高的数组。二维数组以上的数组,统称为多维数组。
二维数组就像是一个由“行”和“列”构成的表单,其中各元素纵横排列,如下图:
定义二维数组的一般形式为:类型名 数组名[常量表达式][常量表达式];
C 语言中二维数组可被看作是一种特殊的一维数组,它的元素又是一个一维数组。例如可以把 a 看作是一个一维数组,它有4个元素a[0],a[1],a[2],a[3],每个元素又是一个包含3个元素的一维数组,如下:
-
a [ 0 ] - - a [ 0 ][ 0 ] a [ 0 ][ 1 ] a [ 0 ][ 2 ]
-
a [ 1 ] - - a [ 1 ][ 0 ] a [ 1 ][ 1 ] a [ 1 ][ 2 ]
-
a [ 2 ] - - a [ 2 ][ 0 ] a [ 2 ][ 1 ] a [ 2 ][ 2 ]
-
a [ 3 ] - - a [ 3 ][ 0 ] a [ 3 ][ 1 ] a [ 3 ][ 2 ]
引用二维数组元素
在定义数组并对其中各元素赋值后,就可以引用二维数组中的元素。引用二维数组元素的表示形式为:
数组名[下标][下标]
例如:a[2][3] 就是表示数组 a 中序号为2的行中序号为3的列的元素。
注意:数组元素可以出现在表达式中,也可以被赋值。在引用数组元素时,下标值应在已定义的数组大小的范围内。
二维数组的初始化
二维数组的初始化方法有很多,现介绍最常见的两种:
-
在定义数组时对全部数组元素赋予初值
例如:int a[3][4] = {{1,2,3,4},{5,6,7,8},{9,10,11,12}};
这种赋值方法比较直观,把第一个花括号内的数据赋给第一行的元素,第二个花括号内的数据赋给第二行的元素……,即按行赋值。
也可以将所有数据写在一个花括号内,按数组元素在内存中的排列顺序对各元素赋初值,如:
int a[3][4] = {1,2,3,4,5,6,7,8,9,10,11,12}
还可以只对部分元素赋初值,如:
int a[3][4] = {{1},{5},{9}}
它的作用是只对各行第1列(即序号为0的列)的元素赋初值,其余元素值自动为0。
字符数组
用来存放字符数据的数组是字符数组。字符数组中的一个元素存放一个字符。
定义字符数组的方法与定义数值型数组的方法类似。例如:
字符数组元素
字符数组的初始化
-
char c [ 5 ];
-
c [ 0 ]= 'H' ; c [ 1 ]= 'e' ; c [ 2 ]= 'l' ; c [ 3 ]= 'l' ; c [ 4 ]= 'o' ;
-
引用字符数组元素与引用数值型数组方法类似,只不过引用字符数组中的一个元素,得到的是一个字符。
-
字符数组的初始化方法与数值型数组类似,这里介绍一种不同的初始化方法,即通过字符串处理函数 gets 来初始化。
-
一般形式为:gets(字符数组)
其作用是从终端输入一个字符串到字符数组,并且得到一个函数值。该函数值是字符数组的起始地址。
如执行下面的代码:
-
char str [ 50 ];
-
gets ( str );
从键盘输入Computer后按回车,则将输入的字符串Computer传送给字符数组str,请注意,这里送给数组的共有9个字符,而不是8个字符(9个字符是因包括一个末尾的空字符‘ \0 ’,gets()函数并不读取换行符‘ \n ’,它会把换行符替换成空字符,作为 C 语言字符串结束的标志)。
一般利用 gets 函数的目的是向字符数组输入一个字符串,而不大关心其函数值。 同样地,我们可以用 puts 函数将字符串输出。
例如:
-
char name [ 6 ] = "Hello" ;
-
puts ( name );
输出结果:Hello
字符串结束标志
在 C 语言中,规定了一个字符串结束标志,以字符‘ \0 ’作为结束标志。
因此,在程序中常常依靠检测‘ \0 ’的位置来判定字符串是否结束,而不是根据数组的长度来决定字符串的长度。所以在定义字符数组时,应估计实际字符串长度,保证数组长度始终大于字符串实际长度。
说明:‘ \0 ’代表 ASCII 码为0的字符,从 ASCII 码表中可以查到, ASCII 码为0的字符不是一个可以显示的字符,而是一个“空操作符”,即它什么也不做。用它来作为字符串结束标志不会产生附加的操作或增加有效字符,只是起到一个供辨别的标志。