一.控制语句
1.1if-else语句
if语句概述
if(表达式)
语句块1
else
语句块2
常见形式
简化形式
if(表达式)语句块,例如:if(x>y)printf("%d",x);
阶梯形式
if(表达式1)语句块1
else if(表达式2)语句块2
else if(表达式3)语句块3
else if(表达式4)语句块4
嵌套形式
if()
if ()语句1
else 语句2
else
if() 语句3
else 语句4
注意:
1.语句块,若有若干条语句时,必须用{……}括号起来
2.表达式
1.一般情况下为逻辑表达式或关系表达式
如:if(a==b&&x==y)printf("%d",x);
2.也可以是任意类型(整形,实型,任意性,指针类型)
如:if('a')printf("%d",a);
#include <stdio.h>
#include <stdlib.h>
int main()
{
int a=0;
if(a)
printf("aaaa\n");
else
printf("bbbb\n");
return 0;
}
3.请区分if(x=1)和if(x==1)的不同
例:输入三个数,从小到大排序
#include <stdio.h>
#include <stdlib.h>
int main()
{
int a=5,b=1,c=9;
int t;
if(a>b)
{
t=a;
a=b;
b=t;
}
if(a>c)
{
t=a;
a=c;
c=t;
}
if(b>c)
{
t=b;
b=c;
c=t;
}
printf("%d %d %d\n",a,b,c);
return 0;
}
1.2switch语句
多分支选项结构
switch语句的基本形式
switch(表达式)
{
case 常量表达式1: 语句块1; break;
case 常量表达式2: 语句块2; break;
case 常量表达式n: 语句块n; break;
default : 语句块n+1
}
switch语句的使用
每个常量表达式的值必须各不相同,否则将出现矛盾
当表达式的值与case后面的常量表达式的值相等时,就执行case后面的语句
switch中的表达式可以是整形,字符表达式或枚举
case常量,只起语句标号的作用
break语句用于强行跳出switch体,一般每个case后面应有一个break语句,defalut分支后的break可以省略
多个case可以执行一条语句
#include <stdio.h>
#include <stdlib.h>
int main()
{
int tmp=3;
switch(tmp)
{
case 1:
printf("1\n");
break;
case 2:
printf("2\n");
break;
case 3:
printf("3\n");
break;
default:
printf("not 1 2 3\n");
}
return 0;
}
1.3循环语句
循环查询语句
1.3.1 goto
使用goto完成1-100的求和
#include <stdio.h>
#include <stdlib.h>
int main()
{
int i=1,sum=0;
loop:
if(i<=100)
{
sum=sum+i;
i++;
goto loop;
}
printf("sum=%d \n",sum);
return 0;
}
当程序有多个出口,使用goto把这些出口集中在一处很方便,特别是函数中有很多重复的工作的时候。
无条件跳转易于理解;可以减少嵌套;可以避免那些忘记更新某一个出口点的问题算是帮助编译器做优化
1.3.2while
while语句构成循环
基本形式
while(表达式)
{
statements;
}
循环条件:1.变量初值 2.终止条件 3.变量变化
完成1-100的求和
#include <stdio.h>
#include <stdlib.h>
int main()
{
int i=1,sum=0;
while(i<=100)
{
sum=sum+i;
i++;
}
printf("sum=%d \n",sum);
return 0;
}
1.3.3do-while
do-while构成循环
基本形式
do{
statemens;}while(表达式);
完成1-100的求和
#include <stdio.h>
#include <stdlib.h>
int main()
{
int i=1,sum=0;
do{
sum=sum+i;
i++;
} while(i<=100);
printf("sum=%d \n",sum);
return 0;
}
while和do-while区别是while先判断在执行可能一次都不执行,do-while至少执行一次。
1.3.4for
一般形式
for(expression1;expression2;expression3)
{
statements;
}
执行过程
1.先求解表达式1,初始值
2.求解表达式2,若为真则执行循环体,然后执行步骤三,若为假则执行步骤五
3.求解表达式3
4.转回执行步骤2
5.执行for下面的语句
完成1-100的求和
#include <stdio.h>
#include <stdlib.h>
int main()
{
int i,sum=0;
for(i=1;i<=100;i++)
{
sum=sum+i;
}
printf("sum=%d",sum);
return 0;
}
for语句构成循环
表达式1可以省略,但循环之前应要给循环变量赋值
表达式2可以省略,将陷入死循环
表达式3可以省略,但在循环体中增加循环使变量的值改变的语句
打印九九乘法表
#include <stdio.h>
#include <stdlib.h>
int main()
{
int i=1,j=1;
int sum;
for(i=1;i<=9;i++)
{
for(j=1;j<=i;j++)
{
sum=i*j;
printf("%d*%d=%d\t",i,j,sum);
}
printf("\n");
}
return 0;
}
1.4辅助控制语句
1.4.1 break
用于从循环体内跳出一层循环体,即提前结束循环
break只能用在循环语句和switch语句中
#include <stdio.h>
#include <stdlib.h>
#define PI 3.14
int main()
{
float r=0,area=0;
while(1)
{
for(r=1;r<=10;r++)
{
area=PI*r*r;
if(area>100)
break;
printf("r=%f,area=%f\n",r,area);
}
}
return 0;
}
1.4.2 continue
结束本次循环,接着判定下一次是否执行循环
注意break和continue区别,continue直接结束本次循环,break终止本层循环
#include <stdio.h>
#include <stdlib.h>
#define PI 3.14
int main()
{
int n;
for(n=100;n<=120;n++)
{
if(n%3==0)
continue;
printf("%d\n",n);
}
return 0;
}
1.4.3 return
return 语句的一般形式:return(<表达式>)
主要用于终止包含它的函数的执行;若终止的为主函数,则主函数结束
二.数组
2.1一维数组
构造数据类型之一
数组是有一定顺序关系的若干个变量的集合,组成数组的各个变量称为数组的元素
数组是各元素的数据类型要求相同,要数组名和下标确定,数组可以是一维的也可以是多维的
2.1.1一位数组的定义
1.所谓的一维数组是指只有一个下标的数组,它在计算机内存中是连续存储的
2.在C语言中,一维数组的说明一般形式如下:
<存储类型><数据类型> <数组名>[<表达式>]
例如:int a[6]:
数组名表示内存首地址,是地址常量。sizeof(数组名)是数组占用的总内存空间
编译时分配连续的内存,内存字节数=数组维数*sizeof(元素数据类型)
注意事项:
C语言对数组不作越界检测,使用时要注意
2.1.2一位数组的引用
数组先定义,再使用;
只能逐个引用数组元素,不能一次性引用整个数组
数组元素表现形式:数组名[下标] (其中,下标可以是常量或者整形表达式)
例如:
int a[10];
printf("%d",a); //错误写法
for(i=0;i<10;i++)
printf("%d",,a[i]); //正确写法
2.1.3一位数组的初始化
1.初始化方式:在定义数组的时候,为数组元素赋初值
int a[5]={1,2,3,4,5};
2.说明
1.数组不初始化,其元素值为随机数
2.对static数组元素不赋初值系统默认为0
3.只给部分数组元素赋初值
static int a[5]; | 等价于:a[0]=0;a[1]=0;a[2]=0;a[3]=0;a[4]=0;a[5]=0; |
int a[5]={6,2,3}; | 等价于:a[0]=6;a[1]=2;a[2]=3;a[3]=0;a[4]=0;a[5]=0; |
int a[]={1,2,3,4,5,6}; | 编译系统通过初值个数确定数组维数 |
#include <stdio.h>
#include <stdlib.h>
#define PI 3.14
int main()
{
int a[]={1,2,3,4,5,6},i,n;
n=sizeof(a)/sizeof(int);
for(i=0;i<6;i++)
{
printf("%d \n",a[i]);
}
printf("%d\n",n);
return 0;
}
冒泡排序
重复的走访过要排序的数列,一次比较两个元素,如果顺序错误就交换,走访数列的工作是重复的进行直到没有再需要交换,也就是说数列已经排序完成
#include <stdio.h>
#include <stdlib.h>
#define PI 3.14
int main()
{
int a[]={1,2,13,16,8},i,n,j;
int t=0;
n=sizeof(a)/sizeof(int);
for(i=0;i<n;i++)
{
printf("%d ",a[i]);
}
printf("\n");
for(i=0;i<n-1;i++)
{
for(j=0;j<n-i-1;j++)
{
if(a[j]>a[j+1])
{
t=a[j];
a[j]=a[j+1];
a[j+1]=t;
}
}
}
for(i=0;i<n;i++)
{
printf("%d ",a[i]);
}
return 0;
}
2.2二维数组
2.2.1二维数组的定义
定义方式:(声明时列数不能省略,行数可以)
数据类型 数组名[常量表达式][常量表达式]
例如:
int a[3][4];
float b[2][5];
int c [2][3][4]
元素个数=行数*列数
2.2.2二维数组的存放顺序
原因:内存是一维的
二维数组:按行序优先
二维数组a是由三个元素组成a[0],a[1],a[2]
每个元素a[i] 由包括2个元素的一堆一维数组组成
2.2.3二维数组的引用
形式:数组名[下标][下标]
二维数组元素的初始化
分行初始化
按元素排列顺序初始化
例如:
int a[2][3]={{1,2,3},{4,5,6}};
a[0][0]、a[0][1]、a[0][2]、a[1][0]、a[1][1]、a[1][2]
例如:
int a[][3]={{1},{4,5}}; //一维数组的长度省略
2.3多维数组
具有两个或者两个以上下标的数组称为多维数组。
int c[2][3][4]
c[0][0][0]、c[0][0][1]、c[0][0][2]、c[0][0][3]
c[0][1][0]、c[0][1][1]、c[0][1][2]、c[0][1][3]
c[0][2][0]、c[0][2][1]、c[0][2][2]、c[0][2][3]
c[1][0][0]、c[1][0][1]、c[1][0][2]、c[1][0][3]
c[1][1][0]、c[1][1][1]、c[1][1][2]、c[1][1][3]
三.字符数组和字符串
3.1字符数组
字符数组是元素的数据类型为字符类型的数组
char c[10],ch[3][4];
字符数组的初始化
逐个字符赋值
char ch[5]={'H','e','I','I','o'};
char ch[5]={'a','b','c'};
例如:
char ch[6]={"hello"};
char ch[6]="hello";
char ch[]="hello";
3.2字符串数组
C语言中没有字符串常量,用字符数组处理字符串,字符串结束表示:'\0'
char fruit[][7]={"apple","grape","pear","orange","peach"};
#include <stdio.h>
#include <stdlib.h>
int main()
{
char fruit[][10]={"apple","grape","pear","orange","peach"};
int n=0,m=0,i,j;
n=sizeof(fruit)/sizeof(fruit[0]);
m=sizeof(fruit[0])/sizeof(char);
for(i=0;i<n;i++)
{
for(j=0;j<m;j++)
{
putchar(fruit[i][j] );
}
putchar('\n');
}
return 0;
}
输入一个字符串,将字符串逆序输出
#include <stdio.h>
#include <stdlib.h>
#include<string.h>
#define N 20
int main()
{
char str[N]={0};
int n,i,j,t;
printf("please input str:");
gets(str);
n=strlen(str);
/* for(i=n-1;i>=0;i--)
{
putchar(str[i]);
}
*/
i=0,j=n-1;
while(i<j)
{
t=str[i];
str[i]=str[j];
str[j]=t;
i++;
j--;
}
puts(str);
return 0;
}
3.3字符串函数
C语言库中实现了很多字符串处理的函数
1.strlen,求字符串长度函数
2.strcpy,字符串拷贝函数
3.strcat,字符串连接函数
4.strcmp,字符串比较函数
3.3.1 strlen
字符串长度函数strlen
格式:strlen(字符数组)
功能:计算字符串长度
返回值:返回字符串实际长度,不包括‘\0’在内,遇到'\0'不计算了(strlen是一个函数,sizeof只是一个运算符而已)
\xhh表示十六进制数代表的符号
\ch表示八进制数
#include <stdio.h>
#include <stdlib.h>
#include<string.h>
int main()
{
char s[10]={'a','\0','b','0','c'};
char s1[]="\t a b \v \\ c";
char s2[]="\x69\141";
int n;
n=strlen(s);
printf("%d %d\n",n,sizeof(s));
printf("%d %d\n",strlen(s1),sizeof(s1));
printf("%d %d\n",strlen(s2),sizeof(s2));
puts(s2);
return 0;
}
3.3.2 strcpy
字符串拷贝函数strcpy
格式:strcpy(字符串1,字符串2);
功能:将字符串2拷贝到字符串1中
返回值:返回字符数组1的首地址
说明:
1.字符数组1必须足够大
2.拷贝时'\0'一同拷贝
#include <stdio.h>
#include <stdlib.h>
#include<string.h>
#define N 30
int main()
{
char scr[]="hello";
char des[N];
/*strcpy(des,scr);*/
int i=0,n;
n=strlen(scr);
printf("%d \n",n);
while(i<=n)
{
des[i]=scr[i];
i++;
}
puts(scr);
puts(des);
return 0;
}
3.3.3 strcat
字符串连接函数strcat
格式:strcat(字符数组1,字符数组2)
功能:把字数数组2连接到字符数组1后面
返回值:返回字符数组1的首地址
说明:1.字符数组1必须足够大
2.连接前,两串均以'\0'结束,连接后,串1的'\0'取消,新串最后加'\0'
#include <stdio.h>
#include <stdlib.h>
#include<string.h>
int main()
{
char des[20]="hello";
char scr[]="world";
strcat(des,scr);
puts(scr);
puts(des);
return 0;
}
3.3.4 strcmp
字符串比较函数strcmp
格式:strcmp(字符串1,字符串2)
功能:比较两个字符串
比较规则:对两串从左向右逐个字符比较(ASCII),直到遇到不同字符或'\0'为止
返回值:返回int 型整数
说明:1.字符串1<字符串2,返回负整数
2.字符串1>字符串2,返回正整数
3.字符串1=字符串2,返回0
#include <stdio.h>
#include <stdlib.h>
#include<string.h>
int main()
{
char des[20]="hello";
char scr[]="abc";
printf("%d \n",strcmp(des,scr));
return 0;
}
3.3.5字符串拓展用法
strncpy(p,p1,n),复制指定长度字符串
strncat(p,p1,n),附加指定长度字符串
strcasecmp(p,p1),忽略大小写比较字符串
strncmp(p,p1,n),比较指定长度字符串
strchr(p,c)在字符串中查找指定字符
strstr(p,p1)查找字符串
isalpha()检查是否为字母字符
isupper()检查是否为大写字母字符
islower()检查是否为小写字母字符
isdigit()检查是否为数字
#include <stdio.h>
#include <stdlib.h>
#include<string.h>
int main()
{
char des[]="hello";
char scr[]="world";
//strncpy(des,scr,3);
//strncat(des,scr,3);
strncmp(des,scr,3);
/*puts(des);
puts(scr);*/
printf("%d",strncmp(des,scr,3));
return 0;
}
四.指针
4.1指针的基本用法
C语言中使用指针可以
程序简洁,紧凑,高效
有效的表达复杂的数据类型
动态分布内存
得到多余一个的函数返回值
在计算机内存中,每一个字节单元,都有一个编号,为地址:
编译或函数调用时为其分配内存空间
变量是对程序中数据存储空间的抽象
4.2指针的概念
在C语言中,内存单元的地址称为指针,专门用来存放地址的变量,有时对地址,指针,指针变量不区分,统称为指针(地址==指针)
指针变量的说明
一般形式:
<存储类型> <数据类型> *<指针变量名>
例如:
char *pName;
int a;
指针的存储类型是指针变量本身的存储类型
指针说明时指定的数据类型不是指针变量本身的数据类型;而是指针目标的数据类型,简称为指针的数据类型
指针在说明的同时,也可以被赋初值,叫做指针的初始化
一般形式是:
<存储类型> <数据类型> *<指针变量名>=<地址量>;
例如:
int a , *pa = &a;
int a=1;
在上面的语句中,把变量a的地址作为初值赋予了刚说明的int型指针pa
int a=3;
int *pa = &a;
#include <stdio.h>
#include <stdlib.h>
#include<string.h>
int main()
{
int a=3;
int *pa;
pa=&a;
printf("%p %p %p \n",&a,pa,&pa);
printf("%d %d %d \n",a,*pa,sizeof(pa));
return 0;
}
4.3指针的含义
指针指向内存区域中的数据称为指针的目标
如果它指向的区域是程序的一个变量的内存空间,则这个变量称为指针的目标变量;简称为指针的目标
引入指针要注意程序中的px、*px和&px三种表示方法的不同意义,设px为一个指针,则:
px,指针变量,它的内容是地址量
*px,指针所指向的对象,它的内容是数据
&px,指针变量占用的储存区域的地址,是一个常量
指针赋值运算指的是通过赋值运算符指针变量送一个地址值
向一个指针变量赋值时,送的值必须是地址常量或指针变量,不能是普通的整数()
指针赋值运算常见的有以下几种形式:
1.把一个普通变量的地址赋给一个具有相同数据类型的指针
double x=15,*px;
px=&x;
2.把一个已有地址值的指针变量赋给具有相同数据类型的另一个指针变量
float a,*px,*py;
px=&a;
py=px;
3.把一个数组的地址赋给具有相同数据类型的指针
int a[20],*pa;
pa=a; //等价于 pa = &a[0]
指针:内存单元的地址,指针在64位系统为8个字节,32位系统为4个字节
4.4指针运算
指针运算是以指针变量所存放的地址量作为运算量而进行的运算
指针运算的实质是地址的计算
指针运算的种类是有限的,它只能进行赋值运算,算术运算和关系运算
指针的算术运算见下表:
运算符 | 计算形式 | 意义 |
+ | px+n | 指针向地址大的方向移动n个数据 |
- | px-n | 指针向地址小的方向移动n个数据 |
++ | px++或++px | 指针向地址大的方向移动1个数据 |
-- | px--或--px | 指针向地址小的方向移动1个数据 |
* | px*py | 两个指针之间相隔数据元素的个数 |
指针加减
注意:
不同数据类型的两个指针实行加减整数运算是没有意义的
px+n表示的实际位置的地址量是:
(px)+sizeof(px的类型)*n
px-n表示的实际位置的地址量是:
(px)-sizeof(px的类型)*n
两个指针相减运算
px-py运算的结果是两个指针指向的地址位置之间相隔数据的个数
因此两个指针相减不是两个指针持有的地址值相减的结果
两个指针相减的结果值不是地址量,而是一个整数值,表示两指针之间相隔数据的个数
px++,++px,px--,--px运算
指针的关系运算符
运算符 | 说明 | 例子 |
> | 大于 | px>py |
< | 小于 | px<py |
>= | 大于等于 | px>=py |
<= | 小于等于 | px<=py |
!= | 不等于 | px!=py |
== | 等于 | px==py |
两个指针之间的关系运算符表示它们指向的地址位置之间的关系,指向地址大的指针大于指向地址小的地方指针
指针与一般整数变量之间的关系运算没有意义,但可以和零进行等于或不等于的关系运算判断指针是否为空
#include <stdio.h>
#include <stdlib.h>
int main()
{
int a=10;
int *pa=((void *)0);
printf("%d %p \n",pa,pa);
return 0;
}
4.5指针与数组
在C语言中,数组的指针是指数组在内存中的起始地址,数组元素的地址是指数组元素在内存中的起始地址
一维数组的数组名为一维数组的指针(起始地址)
例如:
double x[18]; //x为数组的起始地址
设指针变量px的地址值等于数组指针x(即指针变量px指向数组的首元素)则:x[i],(px+i),(x+i)和px[i]具有完全相同的功能;访问数组的第i+1个数组元素
int a[10],*p; p=a;
#include <stdio.h>
#include <stdlib.h>
int main()
{
int a[]={1,2,3,4,5,6,7,8,9,10};
int *p,i,n;
p=a;
n=sizeof(a)/sizeof(int);
for(i=0;i<n;i++)
{
printf("%d %d %d %d\n",a[i],*(p+i),*(a+i),p[i]);
}
printf("\n");
return 0;
}
p[i]<==>*(p+i)
注意:
指针变量和数组在访问数组时中元素时,一定条件下其使用方法具有相同的形式,因为指针变量和数组名都是地址量
但指针变量和数组的指针(或叫数组名)在本质上不同,指针变量是地址变量,数组名是地址常量
例如:
int a[]={1,2,3,4,5,6,7,8,9} , *p=a,i;
数组元素的地址正确表达是(D):
(A).&(a+i) (B).a++ (C).&p (D).&p[i]
数组名是地址常量
p++,p-- (对)
a++,a-- (错)
a+1,*(a+2) (对)
数组反序存放
#include <stdio.h>
#include <stdlib.h>
int main()
{
int a[]={1,2,3,4,5,6,7,8,9,10};
int *p1,*p2,n,t;
n=sizeof(a)/sizeof(int);
p1=a;
p2=&a[n-1];
for(t=0;t<n;t++)
{
printf("%d ",a[t]);
}
printf("\n");
while(p1<p2)
{
t=*p1;
*p1=*p2;
*p2=t;
p1++;
p2--;
}
for(t=0;t<n;t++)
{
printf("%d ",a[t]);
}
return 0;
}
4.6指针和二维数组
多维数组就是具有两个或两个以上下标的数组
在C语言中,二维数组的元素联系存储,按行优先存
题目:一级指针遍历二维数组
#include <stdio.h>
#include <stdlib.h>
int main()
{
int a[3][2]={{1,2},{3,4},{5,6}};
int *p1,n,i;
p1=a;
n=sizeof(a)/sizeof(int);
for(i=0;i<n;i++)
{
printf("%d ",*(p1+i));
}
return 0;
}
可以把二维数组看做由多个一维数组组成
比如int a[3][3],含有三个元素,a[0],a[1],a[2]
元素a[0],a[1],a[2]都是一维数组名
二维数组名代表数组的起始地址,数组名加1,是移动一行元素,因此二维数组名常被称为行地址
行指针(数组指针)
存储行地址的指针变量,叫做行指针变量,显示如下:
<存储类型><数据类型> (*<指针变量名>){表达式n};
例如
int a[2][3]; int (*p)[3];
方括号中的常量表达式表示指针加一,移动几个数据
当用行指针操作二维数组时,表达式一般写成1行的元素个数,即列数
使用行指针表示二维数组的某个元素
#include <stdio.h>
#include <stdlib.h>
int main()
{
int a[3][2]={{1,2},{3,4},{5,6}};
int (*p)[2],i,j;
p=a;
printf("%p %p \n",a,a+1);
printf("%p %p \n",p,p+1);
printf("%d %d %d %d\n",a[1][1],p[1][1],*(*(a+1)+1),*(*(p+1)+1));
for(i=0;i<3;i++)
{
for(j=0;j<2;j++)
{
printf("%d %d %d %d \n",a[i][j],p[i][j],*(*(a+i)+j),*(*(p+i)+j));
}
printf("\n");
}
return 0;
}
4.7字符指针和字符串
C语言通过使用字符数组来处理字符串
通常,我们把char数据类型的指针变量称为字符指针变量,字符指针变量与字符有着密切关系它也被用来处理字符串
初始化字符指针是把内存中字符串的首地址赋予指针,并不是把该字符串复制到指针中
char str[]="Hello world";
char *p=str;
在C语言编程中,当一个字符指针指向一个字符串常量时,不能修改指针指向的对象的值
char *p="Hello world";
*p='h';
不使用任何字符串函数,实现字符串函数连接功能
#include <stdio.h>
#include <stdlib.h>
int main()
{
char ch[100]="welcome";
char *p="hello world",*a;
int i=0;
a=p;
while(*(ch+i)!='\0')
{
i++;
}
while(*p!='\0')
{
*(ch+i)=*p;
p++;
i++;
}
*(ch+i)=*p;
p=a;
puts(ch);
puts(p);
return 0;
}