2.1基本数据类型
2.2 顺序结构
2.3选择结构
if语句
switch语句
2.4 循环结构
while语句
例题:计算机求解1+2+3+4…+100?
#include<stdio.h>
int main(){
int n=1;
int sum=0;
while(n<=100){
sum+=n;
n++;
}
printf("%d",sum);
return 0;
}
while条件判断的真假可以使用的技巧
1、如果表达式是“!=0”,则可以省略“!=0”
2、如果表达式是“==0”,则可以省略“==0”,并在表达式前面添加非运算符"!".
例题:使用计算机实现将n(12345)的每一位数字相加,即1+2+3+4+5=15.
#include<stdio.h>
int main(){
int n=12345;
int count=0;
while(n){
count+=n%10;
n=n/10;
}
printf("%d\n",count);
return 0;
}
do…while语句
例题:计算机求解1+2+3+4…+100?
在这里插入#include<stdio.h>
int main(){
int n=1;
int sum=0;
do{
sum+=n;
n++;
}while(n<=100);
printf("%d\n",sum);
return 0;
}
for 语句
例题:计算机求解1+2+3+4…+100?
#include<stdio.h>
int main(){
int n=1;
int sum=0;
for(n=1;n<=100;n++){
sum+=n;
}
printf("%d\n",sum);
return 0;
}
break和continue语句
break语句:结束循环
continue语句:结束本轮循环,提前开始下一次循环。
2.5数组
一维数组
定义:
把相同数据类型的变量组合在一起而产生的数据集合
数组是从某个地址开始连续若干个位置形成的元素集合。
定义格式:
数据类型 数组名[数组大小];
一维数组的初始化:
需要给出用逗号隔开的从第一个元素开始的若干个元素的初值,并用大括号括住。后面未被赋初值的元素将会由不同编译器内部实现的不同而被赋予不同的初值(可能是很大的随机数),一般情况默认初值为0。
#include<stdio.h>
int main(){
int a[10]={5,3,6,5,1,3,87};
for(int i=0;i<10;i++){
printf("a[%d]=%d\n",i,a[i]);
}
return 0
}
递推:分为顺推和逆推
根据一些条件,可以不断让后一位的结果由前一位或前若干位计算得来。
例题:下面程序实现了输入a[0],并将数组中后续元素都赋值为其前一个元素的二倍的功能。
#include<stdio.h>
int main(){
int a[10];
scanf("%d",&a[0]);
printf("a[%d]=%d\n",0,a[0]);
for(int i=1;i<10;i++){
a[i]=2*a[i-1];
printf("a[%d]=%d\n",i,a[i]);
}
return 0;
}
冒泡排序
依次两两比较数组中的是数据,将最大的泡泡(数字)沉到最下面;然后把次大的数据沉到下方,依次进行。
例题:现有一个数组a,其中有5个元素,分别为a[0]=3、a[1]=4、a[2]=1、a[3]=2、a[4]=8,要求把它们按从小到大的顺序排序。
#include<stdio.h>
int main(){
int temp;
int a[10]={3,4,1,2,8};
for(int i=1;i<4;i++){ //进行n-1趟
for(int j=0;j<5-i;j++){
if(a[j]>a[j+1]){
temp=a[j];
a[j]=a[j+1];
a[j+1]=temp;
}
}
}
for(int i=0;i<5;i++){
printf("%d",a[i]);
}
return 0;
}
二维数组
格式如下:
数据类型 数组名 [第一维大小] [第二维大小]
访问二维数组:
给出第一维和第二维的下标。
初始化:
和一维数组一样,二维数组也可以在定义时进行初始化。二维数组在初始化时,需要按第一维的顺序依次用大括号给出第二维的初始化情况,然后将它们用逗号分割,并用大括号全部括住。
#include<stdio.h>
int main(){
int a[5][6] = {{3,1,2},{8,4},{},{1,2,3,4,5}};
for(int i=0;i<5;i++){
for(int j=0;i<6;j++){
printf("%d",a[i][j]);
}
printf("\n");
}
return 0;
}//第1、2、4行都赋予了初值,第三行使用大括号{}跳过,剩下的部分均被默认赋值为0.
例题:将两个数组对应位置元素相加,并将结果存放在另一个二维数组中。
#include<stdio.h>
int main(){
int a[3][3];
int b[3][3];
for(int i=0;i<3;i++){
for(int j=0;j<3;j++){
scanf("%d",&a[i][j]);
}
}
for(int i=0;i<3;i++){
for(int j=0;j<3;j++){
scanf("%d",&b[i][j]);
}
}
int c[3][3];
for(int i=0;i<3;i++){
for(int j=0;j<3;j++){
c[i][j]=a[i][j]+b[i][j];
}
}
for(int i=0;i<3;i++){
for(int j=0;j<3;j++){
printf("%d ",c[i][j]);
}
printf("\n");
}
return 0;
}
提醒:如果数组大小较大,则需要将其定义在主函数外面,否则会使程序异常退出,原因是函数内部申请的局部变量来自系统栈,允许申请的空间较小;而函数外部申请的全局变量来自静态存储区,允许申请的空间较大。
memset(对元素中每个元素赋予相同的值)
一般来说,给数组中每个元素赋相同的值有两种方法:memset函数 、fill函数
memset函数的格式:
memset(数组名,值,sizeof(数组名));
使用memset需要在程序开头添加string.h头文件,且只建议初学者使用memset赋0或-1.这是因为memset使用的是字节赋值,即对每个字节赋同样的值,这样组成int型的4个字节就会被赋成相同的值。由于0的二进制补码为全0,-1的二进制补码为全1,不容易弄错。如果对数组赋其他数字,需要使用fill函数(memset速度快)。
实例:
#include<stdio.h>
#include<string.h>
int main(){
int a[5]={1,2,3,4,5};
memset(a,0,sizeof(a));//赋初值0
for(int i=0;i<5;i++){
printf("%d",a[i]);
}
printf("\n");
memset(a,-1,sizeof(a));//赋初值-1
for(int i=0;i<5;i++){
printf("%d",a[i]);
}
printf("\n");
return 0;
}
字符数组
1、字符数组的初始化
和普通数组一样,字符数组也可以初始化,其方法也相同,实例如下
#include<stdio.h>
int main() {
char str[15]={'G','o','o','d',' ','s','t','o','r','y','!'};
for(int i=0;i<11;i++){
printf("%c",str[i]);
}
return 0;
}
除此之外,字符数组也可以通过直接赋值字符串来初始化(仅限于初始化,程序其他位置不允许这样直接赋值整个字符串),实例如下:
#include<stdio.h>
int main(){
char str[15]="Good Story!";
for(int i=0;i<11;i++){
printf("%c",str[i]);
}
return 0;
}
2、字符数组的输入输出
字符数组就是char数组,当维度是一维时可以当作“字符串”。当维度是二维时可以当作字符串数组,即若干字符串。
字符数组的输入:scanf、getchar、gets;
字符数组的输出:printf、putchar、puts
(1)scanf输入,printf输出
scanf对字符类型有%c和%s两种格式。%c用来输入单个字符,%s用来输入一个字符串并存在字符数组里。%c格式能识别空格和换行并将其输入,%s通过空格和换行来识别一个字符串的结束。
(2)getchar输入,putchar输出
分别用来输入和输出单个字符。
简单举一个二维字符数组的例子。
#include<stdio.h>
int main(){
char str[5][5];
for(int i=0;i<5;i++){
for(int j=0;j<5;j++){
str[i][j]=getchar();
}
getchar();//把输入中每行末尾的换行符吸收掉
}
for(int i=0;i<5;i++){
for(int j=0;j<5;j++){
putchar(str[i][j]);
}
putchar('\n');
}
return 0;
}
(3)gets输入,puts输出
gets用来输入一行字符串(注意:gets识别换行符\n作为输入结束,因此scanf完一个整数后,如果要使用gets,需要先用getchar接收整数后的换行符),并将其存放于一维数组(或二维数组的一维)中;puts用来输出一行字符串,即将一维数组(或二维数组的一维)在界面上输出,并紧跟着一个换行。
#include<stdio.h>
int main(){
char str1[20];
char str2[5][10];
gets(str1);
for(int i=0;i<3;i++){
gets(str2[i]);
}
puts(str1);
for(int i=0;i<3;i++){
puts(str2[i]);
}
return 0;
}
3、字符数组的存放方式
由于字符数组是由若干个char类型的元素组成,因此字符数组的每一位都是一个char字符。除此之外,在一维字符数组(或是二维数组的第二维)的末尾都有一个空字符\0,以表示存放的字符串的结尾。空字符\0在使用gets或scanf输入字符串时会自动添加在输入的字符串后面,并占用一个字符位,而puts与printf就是通过识别\0作为字符串的结尾来输出的。
提醒1:结束符\0的ASCII码为0,即空字符NULL,占用一个字符位,因此开字符数组的时候记得字符数组的长度要比实际存储字符串的长度至少多1.(int型数组的末尾不需要加\0,只有char型数组需要。\0和空格不是同一个东西,空格的ASKII码为32)
提醒2:如果不是使用scanf函数的%s格式或gets函数输入字符串(例如使用getchar),要在输入的每个字符串后加“\0",否则printf和puts输出字符串会因无法识别字符串末尾而输出一大堆乱码。
string .h头文件
(包含许多用于字符数组的函数)
1、strlen()
得到字符数组中第一个\0前的字符的个数
其格式为:strlen(字符数组);
#include<stdio.h>
#include<string.h>
int main(){
char str[10];
gets(str);
int len=strlen(str);
printf("%d\n",len);
return 0;
}
2、strcmp()
返回两个字符串大小的比较结果,比较原则是按照字典序。
其格式为:strcmp(字符数组1,字符数组2)
字符数组1<字符数组2,则返回一个负整数
字符数组1=字符数组2,则返回0
字符数组1>字符数组2,则返回一个正整数
#include<stdio.h>
#include<string.h>
int main(){
char str1[50],str2[50];
gets(str1);
gets(str2);
int cmp=strcmp(str1,str2);
if(cmp<0) printf("str1<str2\n");
else if(cmp>0) printf("str1>str2\n");
else printf("str1==str2\n");
return 0;
}
3、strcpy
把一个字符串复制给另一个字符串
其格式如下:strcpy(字符数组1,字符数组2)
(这里的复制包括了结束符\0)
#include<stdio.h>
#include<string.h>
int main(){
char str1[50],str2[50];
gets(str1);
gets(str2);
strcpy(str1,str2);
puts(str1);
return 0;
}
4、strcat()
把一个字符串接到另一个字符串后面,
其格式为:strcat(字符数组1,字符数组2)
#include<stdio.h>
#include<string.h>
int main(){
char str1[50],str2[50];
gets(str1);
gets(str2);
strcat(str1,str2);
puts(str1);
return 0;
}
sscanf与sprintf
scanf("%d",&n);
printf("%d",n);
相当于
scanf(screen,"%d",&n);//把screen的内容以“%d”的格式传输到n中
printf(screen,"%d",n); //把n以“%d”的格式传输到screen上
sscanf(str,"%d",&n);//sscanf的格式
sprintf(str,"%d",n); //sprintf的格式
#include<stdio.h>
int main(){
int n;
char str[100]="123";
sscanf(str,"%d",&n);
printf("%d\n",n);
return 0;
}//输出123
#include<stdio.h>
int main(){
int n=223;
char str[100];
sprintf(str,"%d",n);
printf("%s\n",str);
return 0;
}//输出223
2.6函数
函数的定义
基本语法格式:
返回类型 函数名称(参数类型 参数){
函数主体
}
#include<stdio.h>
int judge(int x){
if(x>0) return 1;
else if(x==0) return 0;
else return -1;
}
int main(){
int a,ans;
scanf("%d",&a);
ans=judge(a);
printf("%d\n",ans);
return 0;
}
(1)全局变量
全局变量是指在定义之后的所有程序段内都有效的变量(定义在所有函数之前)
#include<stdio.h>
int x;
void change(){
x=x+1;
}
int main(){
x=10;
change();
printf("%d\n",x);
return 0;
}
(2)局部变量
与全局变量相对,局部变量定义在函数内部,且只在函数内部生效,函数结束时局部变量销毁。
#include<stdio.h>
void change(int x){
x=x+1;
}
int main(){
int x=10;
change(x);
printf("%d\n",x);
return 0;
}
再谈main函数
主函数对一个程序来说只有一个,无论主函数在哪个位置,整个程序一定是从主函数的第一句语句开始执行,然后在需要调用其他函数时才去调用。
int main(){
...
return 0;
}
无参函数;返回类型为int型,在函数主体的最后返回了0.main函数返回0的意义在于告知系统程序程序正常终止。
以数组作为函数参数
数组作为参数时,参数中数组的第一维不需要填写长度(如果是二维数组,那么第二维需要填写长度),实际调用时也需要填写数组名。
最重要的是:数组作为参数时,在函数中对数组元素的修改就等同于对原数组的修改。
示例如下:
#include<stdio.h>
void change(int a[],int b[][5]){
a[0]=1;
a[1]=3;
a[2]=5;
b[0][0]=1;
}
int main(){
int a[3]={0};
int b[5][5]={0};
change(a,b);
for(int i=0;i<3;i++){
printf("%d\n",a[i]);
}
return 0;
}
数组可以作为参数,但是不允许作为返回类型出现。如果想要返回数组,只能用以上方法,将想要返回的数组作为参数传入。
函数的嵌套调用
#include<stdio.h>
int max_2(int a,int b){
if(a>b) return a;
else return b;
}
int max_3(int a,int b,int c){
int temp=max_2(a,b);
temp=max_2(temp,c);
return temp;
}
int main(){
int a,b,c;
scanf("%d%d%d",&a,&b,&c);
printf("%d\n",max_3(a,b,c));
return 0;
}
函数的递归调用
函数自己调用自己
#include<stdio.h>
int F(int n){
if(n==0) return 1;
else return F(n-1)*n;
}
int main(){
int n;
scanf("%d",&n);
printf("%d\n",F(n));
return 0;
}