C语言笔记

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;
}

使用时注意下面事项:
  1. switch 后面括号内的“表达式”,其值的类型应为 整数类型(包括字符串)
  2. 执行 switch 语句时,先计算 swith 后面的“表达式”的值,然后将它与各 case 标号比较,如果与某一个 case 标号中的常量相同,流程就转到此 case 标号后面的语句。如果没有与 switch 表达式相匹配的 case 常量,流程转去执行 default 标号后面的语句。
  3. 可以没有 default 标号,此时,如果没有与 switch 表达式相匹配的 case 常量,则不执行任何语句,流程转到 switch 语句的下一个语句。
  4. 各个 case 语句标号出现次序不影响执行结果。
  5. 每一个 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;
说明:
  1. 左边的 int 类型是在定义指针变量时必须指定的基类型, 指针变量的基类型用于表示指针变量可以指向的变量的类型;
  2. 指针变量前面的 * 表示该变量的类型为指针型变量;
  3. 指针变量名是 pointer_1 pointer_2 ,而不是 * pointer_1 * pointer_2
在引用指针变量时,可以有以下两种情况:
  • 给指针变量赋值
例如:
​​​​​​​ 
int * p;
int a = 3;
p = &a; // 把 a 的地址赋给指针变量 p
这样,指针变量 p 的值就是变量 a 的地址,也可以说 p 指向 a 。
注意:&为取地址运算符,&a 表示 a 的地址。
  • 引用指针变量指向的变量
例如:
  1. int * p ;
  2. int a = 3 ;
  3. p = & a ;
  4. printf ( "%d" ,* p );
便可以以整数形式输出指针变量 p 所指向的变量的值,即变量 a 的值 3
注意:* 为指针运算符,*p 代表指针变量 p 所指向的对象
如有以下赋值语句:* p = 1,表示将整数1赋给指针 p 所指向的变量,相当于a = 1

指向数组元素的指针

一个指针变量既可以指向变量,也可以指向数组元素(即把某一个元素的地址放到一个指针变量中)。
例如:
  1. int a [ 5 ] = { 1 , 3 , 5 , 7 , 9 };
  2. int * p ;
  3. 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);
注意事项:
  1. 定义指向函数的指针变量,并不意味着这个指针变量可以指向任何函数,它只能指向在定义时指定的类型的函数;
  2. 如果要用指针调用函数,必须先使指针变量指向该函数;
如:p = max; // max为已定义的函数的函数名
  1. 在给函数指针变量赋值时,只须给出函数名而不必给出参数;
  2. 对指向函数的指针变量不能进行算术运算;
  3. 用函数指针变量调用函数时,只须将 *p 代替函数名即可( p 为指针变量名),在 *p 之后的括号中根据需要写上实参。
如:c = (*p)(a,b);

函数的递归调用

在调用一个函数的过程中又出现直接或间接地调用该函数本身,称为函数的递归调用。
C语言函数的参数会出现在两个地方,分别是函数定义处和函数调用处,这两个地方的参数是有区别的。

形参(形式参数)

在函数定义中出现的参数可以看做是一个占位符,它没有数据,只能等到函数被调用时接收传递进来的数据,所以称为 形式参数 ,简称 形参

实参(实际参数)

函数被调用时给出的参数包含了实实在在的数据,会被函数内部的代码使用,所以称为 实际参数 ,简称 实参
形参和实参的功能是传递数据,发生函数调用时,实参的值会传递给形参。

数组作为函数参数

数组可以作为函数的参数使用,进行数据传送。
数组用作函数参数有两种形式,一种是把数组元素(下标变量)作为实参使用;另一种是把数组名作为函数的形参和实参使用。
数组元素作函数参数
数组元素就是下标变量,它与普通变量并无区别。 因此它作为函数实参使用与普通变量是完全相同的,在发生函数调用时,把作为实参的数组元素的值传送给形参,实现单向的值传送。
数组名作为函数参数
用数组名作函数参数与用数组元素作实参有几点不同:
  • 数组元素(下标变量)作为实参
  1. 形参数组和实参数组类型必须一致,否则出错;
  2. 在函数形参表中,允许不给出形参数组的长度,或用一个变量来表示数组元素的个数;
  3. 形参数组和实参数组长度可以不相同,因为在调用时,只传递首地址而不检查形参数组的长度。★
  4. 数组名作为函数参数
  5. 用数组元素作函数参数不要求形参也必须是数组,但是用数组名作函数参数时,则要求形参和相对应的实参都是类型相同的数组;
  6. 在 C 语言中,数组名除作为变量的标识符之外,数组名还代表了该数组在内存中的起始地址,当数组名作函数参数时,实参与形参之间不是“值传递”,而是“地址传递”,实参数组名将该数组的真实地址传给形参数组,两个数组共享一段内存单元,编译系统不再为形参数组分配存储单元;//★ 数组名作形参(无[]),为直接导入数组内全部元素
  7. 在变量做函数参数时,所进行的值传递是单向的。即只能从实参传向形参,不能从形参传回实参。

字符串函数的使用

在使用字符串函数前必须使用以下命令包含头文件:#include <string.h>
用来求字符串长度的 strlen 函数。
例如:
​​​​​​​
char str[]="hello";
int l = strlen(str);
printf("%d",l);
输出结果为:5

数组

一维数组

在程序中可以使用下标变量,即说明这些变量的整体为数组,数组中的每个变量的数据类型是相同的。当数组中每个元素都只带有一个下标时,称这样的数组为一维数组。
定义一维数组的一般形式为:
  1. 类型名 数组名[常量表达式];
例如,下面是定义一个整型数组,数组名为 a ,此数组有10个整型元素:
  1. int a [ 10 ];
定义数组需遵循的规则:
  1. 数组名的命名规则和变量名相同,遵循标识符命名规则。
  2. 在定义数组时,需要指定数组中元素的个数,方括号中的常量表达式用来表示元素的个数,即数组长度。
例如上例中,指定 a[10] ,表示 a 数组有10个元素。注意,下标是从0开始的,这10个元素是 a[0]~a[9] ,请特别注意,按上面的定义,不存在数组元素 a[10] 。
  1. 常量表达式中可以包括常量和符号常量。如 int a[3+5]; 是合法的,但不能包含变量,如 int a[n] 是不合法的。
定义数组需遵循的规则:
  1. 数组名的命名规则和变量名相同,遵循标识符命名规则。
  2. 在定义数组时,需要指定数组中元素的个数,方括号中的常量表达式用来表示元素的个数,即数组长度。
例如上例中,指定 a[10] ,表示 a 数组有10个元素。注意,下标是从0开始的,这10个元素是 a[0]~a[9] ,请特别注意,按上面的定义,不存在数组元素 a[10] 。
  1. 常量表达式中可以包括常量和符号常量。如 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个元素的一维数组,如下:
  1. a [ 0 ] - - a [ 0 ][ 0 ] a [ 0 ][ 1 ] a [ 0 ][ 2 ]
  2. a [ 1 ] - - a [ 1 ][ 0 ] a [ 1 ][ 1 ] a [ 1 ][ 2 ]
  3. a [ 2 ] - - a [ 2 ][ 0 ] a [ 2 ][ 1 ] a [ 2 ][ 2 ]
  4. 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

字符数组

用来存放字符数据的数组是字符数组。字符数组中的一个元素存放一个字符。
定义字符数组的方法与定义数值型数组的方法类似。例如:
字符数组元素
字符数组的初始化
  1. char c [ 5 ];
  2. c [ 0 ]= 'H' ; c [ 1 ]= 'e' ; c [ 2 ]= 'l' ; c [ 3 ]= 'l' ; c [ 4 ]= 'o' ;
  3. 引用字符数组元素与引用数值型数组方法类似,只不过引用字符数组中的一个元素,得到的是一个字符。
  4. 字符数组的初始化方法与数值型数组类似,这里介绍一种不同的初始化方法,即通过字符串处理函数 gets 来初始化。
  5. 一般形式为:gets(字符数组)
其作用是从终端输入一个字符串到字符数组,并且得到一个函数值。该函数值是字符数组的起始地址。
如执行下面的代码:
  1. char str [ 50 ];
  2. gets ( str );
从键盘输入Computer后按回车,则将输入的字符串Computer传送给字符数组str,请注意,这里送给数组的共有9个字符,而不是8个字符(9个字符是因包括一个末尾的空字符‘ \0 ’,gets()函数并不读取换行符‘ \n ’,它会把换行符替换成空字符,作为 C 语言字符串结束的标志)。
一般利用 gets 函数的目的是向字符数组输入一个字符串,而不大关心其函数值。 同样地,我们可以用 puts 函数将字符串输出。
例如:
  1. char name [ 6 ] = "Hello" ;
  2. puts ( name );
输出结果:Hello
字符串结束标志
在 C 语言中,规定了一个字符串结束标志,以字符‘ \0 ’作为结束标志。
因此,在程序中常常依靠检测‘ \0 ’的位置来判定字符串是否结束,而不是根据数组的长度来决定字符串的长度。所以在定义字符数组时,应估计实际字符串长度,保证数组长度始终大于字符串实际长度。
说明:‘ \0 ’代表 ASCII 码为0的字符,从 ASCII 码表中可以查到, ASCII 码为0的字符不是一个可以显示的字符,而是一个“空操作符”,即它什么也不做。用它来作为字符串结束标志不会产生附加的操作或增加有效字符,只是起到一个供辨别的标志。
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值