基本概念和语法点

绪论

  • C语言发展历程:机器语言-汇编语言-高级语言
  • 程序错误分3种。1、语法错误通过编译器发现;2、逻辑错误通过调试查找;3、运行异常错误:对程序运行环境的非正常情况考虑不周
  • C程序必须经过编译、链接后生成可执行文件(.exe)才能运行
  • /……/用于行注释,/* …… */用于对程序块的注释
  • C语音系统以文件为单位编译源程序,程序由函数组成

数据基本类型

  • 整型默认long、designed,四字节,取值 -231~231-1,无符号 0~232-1,短整型short int 两字节,-215~215-1
  • 实型默认double,即3.14f为float,3.14为double,float占4字节/小数点后6位/%f,double占8字节/小数点后12位/%lf。常量后加l或L表示长整型,加u或U表示无符号,加f或F表示float
  • 10-3:1e-3,e或E前面必须有数字,后面必须是整数
  • 八进制数:数字前加0,0111是73,-0111是-73;十六进制数:数字前加0x,0x111是273
  • \t:8个空格;\r:代替该行最开始相等数目的字符("1239226\r561"输出为5619226);\b:光标左移并覆写(“12345\b\b\b\b678”,光标在5右边,移动4次到1的右边,故输出为16785)
  • '\012’转义表示ASCII码为10即换行
  • 区分:'a’为字符常量,占1字节,"a"为字符串,占2字节
  • 实现四舍五入:
float a=1.23456;//保留两位
int i;
i=a*100+0.5;
a=i/100;//保留几位就用10的几次方

逻辑运算短路性质

当使用逻辑与运算符(&&)连接多个条件时,如果其中一个条件为假,则整个表达式的结果必定为假。因此,如果在计算过程中遇到一个假条件,后面的条件将不会被计算,直接返回假作为整个表达式的结果。
逻辑或运算符(||)同理。当使用逻辑或运算符连接多个条件时,如果其中一个条件为真,则整个表达式的结果必定为真。

三目运算符

格式:条件表达式 ? 表达式1 : 表达式2。例:

int score = 80;
String level = (score >= 90) ? "优秀" : ((score >= 80) ? "良好" : "及格");

在上述代码中,根据score的分数不同,返回不同的等级。如果分数大于等于90,则返回"优秀";如果分数大于等于80,则返回"良好";否则返回"及格"。

运算符的优先级和结合性

优先级从高到低:
() 、[]、->、.
!、++、-- (右结合)
*、 / 、%
+、-
<、>、<=、>=
==、!=
&&
||
?:
=、+=、-=(右结合)

宏定义和宏替换

注意:替换时不要人为加括号,如定义define N 1+2(注意没有分号)则程序中N*2=5

函数的输入与输出

  • 输出%:“%%”;输出\:“\”;输出":" \ " "
  • 格式字符:%5d表示至少输出5字符,空格填左边,%-5d空格填右边;%m.nf输出float至少占m列,小数点也算一列,其中小数n位,四舍五入
  • scanf无法输入空格

基本结构与基本语句

  • 程序=算法+数据结构
  • 基本结构:顺序、分支、循环
  • 5种C基本语句:表达式语句、控制语句、函数调用语句、复合语句、空语句
  • 在switch语句中,每个case后面都需要添加break语句,如果忘记添加break语句,程序将会继续执行下一个case中的代码;switch中的default可省

变量

1 作用域

1、局部变量的作用范围仅限于定义它的函数内部,而全局变量定义在函数外部,从定义处起作用
2、局部变量的生命周期只在函数执行期间存在,而全局变量的生命周期在整个程序执行期间都存在。

2 生存期

1、动态变量auto(默认类型)的内存管理由程序员手动控制,需要在适当的时候分配和释放内存空间,再次调用时重新分配内存,只在本函数起作用;
2、静态变量static的内存管理由编译器自动完成,无需程序员干预,且生存周期延长,调用结束不释放内存,下一次调用继续用。//函数调用形参不能是静态变量

  • 一个编译后的C程序右4个内存分区
    程序代码区
    静态数据区:存放全局变量和静态变量
    //全局变量不能用表达式定义,如int a=1,b=2,c=a+b;是错误的
    堆区
    栈区:存放局部变量

数组

  • 字符数组初始化:char s[]=“Asoul”;(夹带私货hh)也可以用get(s)和put(s)整体输入输出

  • 注意:char s[5]={‘A’,‘s’,‘o’,‘u’,‘l’};此种形式不是字符串,无字符串结束标志,故只是普通的一维字符数组,不能由put(s)输出,只能用%c逐个输出

  • int a[2][3]={1,2,3,4,5,6},(*p)[3]=NULL;p=a;程序中给行指针变量p赋值后,p指向a[0],即p的值为&a[0],即行地址,而不是a[0][0];输出a[i][j]可以用p[i][j]、*(p[i]+j)、*(*(p+i)+j)、(*(p+i))[j]代替,若用列指针,则用*(p+i*3+j),其中3代表每一行元素的个数

  • 区分 int (*p)[4] 和 int *p[4]
    int (*p)[4] 是一个指针。p 可以指向一个包含4个整数的数组,通过 p可访问和操作该数组中的元素。例如,(p+1)我们可以访问数组中的第二个元素。
    int *p[4]是一个包含4个指针的数组,每个指针可以指向一个整数变量。通过 p[i],我们可以访问和操作第i个指针指向的整数。例如,(p[1])我们可以访问第二个指针指向的整数。

  • 易错
    1、int *p,m=1,n;则用scanf("%d",&n);*p=n;对p赋值是错误的,因为p没有赋初值;而p=&n;*p=n;正确,p=&n对p赋予初值
    2、char a[30],*p=a;p="asoul";不能将字符串保存到数组a中,因为将p指向字符串后,p就不再指向数组a了,正确的保存方式:strcpy(p,"asoul");
    3、char a[]="hello",*p="hello";sizeof(a)为6,sizeof(p)=2

结构体

  • 结构体数据类型的定义格式:
struct student//student为结构体类型名
{
   int num;
   char name[20];
   float score;
}
  • 初始化
    a.struct student stu1={11,"shuo",99.9};
    b.
struct student//结构体类型名student可省
{
      int num;
      char name[20];
      float score;
}stu1={11,"Shuo",99.9};
  • 使用方法
#include <stdio.h>
#include <string.h>
struct student
{
	int num;
	char name[20];
	struct information{int Class;float score;}in;
};

int main()
{
	struct student stu1;
	stu1.num=1211;
	strcpy(stu1.name,"Gabe");
	stu1.in.score=99.9;
	printf("%d %s %.1f\n",stu1.num,stu1.name,stu1.in.score);
	return 0;
}
  • 指向结构体的指针
    格式:struct student *p;
    结构体指针变量引用成员的形式有3中:
    若有声明:struct student stu1,*p=&stu1;
    stu1.num=101/(*p).num=101/p->num=101;都可以将stu1的num赋值为101
  • 指向结构体数组的指针变量
  • 若有声明:struct student stu[3],*p=stu;
    stu[0].num=101;(*p).num=101;p->num=101;都可以将stu[0]的num赋值为101
int main()
{
	struct student stu[5],*p=stu;
    strcpy((*(p+2)).name,"Shuo");
	printf("%s",(p+2)->name);
	return 0;
}

注意:->优先级高于++,故以下一段程序输出102:

int main()
{
	struct student stu[5],*p=stu;
	p->num=101;
	printf("%d",++p->num);
	return 0;
}

枚举类型

enum Weekday {
    Monday=1,
    Tuesday,
    Wednesday,
    Thursday,
    Friday,
    Saturday,
    Sunday
}workday,weekend;

指定Monday=1,后面的枚举元素的值依次加一,若没有指定,则从0开始
weekend=Saturday;printf("%d",weekend);则输出6

文件

  • 文件操作基本步骤:打开-使用-关闭
  • 文件指针变量的声明:格式FILE *文件指针变量名
    说明:FILE实际上是结构体类型名,必须大写,包括在#include <stdio.h>z中
  • 文件常用函数
    (1)打开文件,格式:文件指针名=fopen("文件名","使用文件方式");
    (2)关闭文件,格式:fclose(文件指针名);
    (3)fprintf(文件指针名,"格式控制字符串",输出表列);例如fprintf(fp,"%d,%6.2f",i,t);将i和t按%d,%6.2f的格式输出到fp指向的文件中
    (4)fscanf(文件指针名,"格式控制字符串",输入表列);例如fscanf(fp,"%d,%6.2f",&i,&t);将文件中的%d赋值给i,将%6.2f赋值给t
    (5)
    c=fgetc(fp);//从fp指针指向的文件中读取一个字符赋给变量c,
    fputc(c,fp);//把变量中的字符写到fp指针指向的文件
    (6)
    fputs("Hello",fp);
    fgets(str,10,fp);//从fp指针指向的文件中读9个字符到数组str中,因为要包括最后的’\0’
    若用fscanf:fscanf(fp,"%s",str);读入字符串时,遇换行符或文件尾(EOF,代表值为-1)结束,并在最后加’\0’

以下程序读懂即可:

#include <stdio.h>

int main()
{
	char s1[80],s2[80];
	int a,b;
	FILE *fp;
	if((fp=fopen("test","w"))==NULL)
		puts("can't open file");
	fscanf(stdin,"%s%d",s1,&a);//从键盘输入
	fprintf(fp,"%s %d",s1,a);//写入文件test
	fclose(fp);
	if((fp=fopen("test","r"))==NULL)
		puts("can't open the file");
	fscanf(fp,"%s%d",s2,&b);//从文件test中读取
	fprintf(stdout,"%s %d",s2,b);//输出到屏幕
	fclose(fp);
	return 0;
}

程序设计

1、反序数、数的拆分

(1)反序数

函数功能:输入一个数,将其逆序输出

#include<stdio.h>
int main()
{
	int n,inverse_n=0;
	scanf("%d",&n);

	while(n!=0)
	{
		inverse_n=inverse_n*10+n%10;
		n=n/10;
	}

	printf("%d",inverse_n);
	return 0;
}

(2)数的拆分

a.水仙花数:一个三位数,其各位数字的立方和等于本身。
函数功能:输出所有的水仙花数。

#include<stdio.h>
int judge(int n);

int main()
{
	int i;
	for(i=100;i<1000;i++)
		if(judge(i))printf("%d  ",i);
	return 0;
}

int judge(int n)
{
	int t,k=n,sum=0;
	while(k!=0)
	{
		t=k%10;
		sum+=t*t*t;
		k=k/10;
	}
	if(sum==n)return 1;
	return 0;
}

b.同构数:出现在其平方数的右边,如5出现在25的右边,25出现在625的右边,故5和25为同构数。
函数功能:找出2~99中所有的同构数。

#include<stdio.h>
int main()
{
	int i;
	for(i=2;i<10;i++)
	{
		if(i*i%10==i)printf("%d  ",i);
	}
	for(i=11;i<100;i++)
	{
		if(i*i%100==i)printf("%d  ",i);
	}
	return 0;
}

总结:n%10得到n的最后一位,n/10的m次方得到的数是原来的n去掉后面的m位。

2、素数的判定

a.素数

除了1和本身外没有其他因数的数。
函数功能:找出2~99内所有的素数。/判断一个数是否为素数类似

#include<stdio.h>
int prime_number(int n);
int main()
{
	int i;
	for(i=2;i<100;i++)
		if(prime_number(i))printf("%d  ",i);
	return 0;
}

int prime_number(int n)
{
	int i;
	for(i=2;i<n;i++)
		if(n%i==0)return 0;
	return 1;
}

b.超级素数

一个素数,依次去掉最低位,若得到的数均为素数,且各数字不为0,则称为超级素数
函数功能:查找100~9999中所有的超级素数

#include<stdio.h>
int prime_number(int n);
int super_prime_number(int n);
int main()
{
	int i;
	for(i=100;i<10000;i++)
		if(super_prime_number(i))printf("%d  ",i);
	return 0;
}

int prime_number(int n)
{
	int i;
	if(n<2) return 0;//1不是素数
	for(i=2;i<n;i++)
		if(n%i==0)return 0;
	return 1;
}

int super_prime_number(int n)
{
	while(n!=0)
	{
		if(prime_number(n)==0)return 0;
		n=n/10;//去掉最低位
	}
	return 1;
}

(不同定义版本的超级素数)若依次去掉最高位得到的数为素数:

int super_prime_number(int n)
{
	int i;
	if(prime_number(n%10)==0)return 0;//先判断最后一位
	while(n>10)
	{
		if(prime_number(n)==0)return 0;
		i=1;
	    while(n/i!=0)
	    {
		    i*=10;
	    }
	    n=n%(i/10);//去掉最高位
		if(n<i/100)return 0;//除去含0的数
	}
	return 1;
}

3、斐波那契数列

Fib(n)=Fib(n-1)+Fib(n-2),Fib(0)=Fib(1)=1;
函数功能:求Fibonacci数列前20项并输出。

#include<stdio.h>
int Fib(int n);
int main()
{
	int i;
	for(i=0;i<20;i++)
		printf("%d  ",Fib(i));
	return 0;
}

int Fib(int n)
{
	if(n==0||n==1) return 1;
	else return Fib(n-1)+Fib(n-2);
}

4、最大公约数和最小公倍数

a.最大公约数

#include<stdio.h>
int max_common_divisor(int a,int b);
int main()
{
	int a,b,c;
	scanf("%d %d",&a,&b);
	c=max_common_divisor(a,b);
	printf("%d",c);
	return 0;
}

int max_common_divisor(int a,int b)
{
	int n;
	while(a%b!=0)
	{
		n=a%b;
		a=b;
		b=n;
	}//辗转相除法
	return n;
}

b.最小公倍数

最小公倍数等于上述程序中的a*b/c,只需将printf行改为printf("%d",a*b/c);即可。

5、有条件的求和、求积

a.输入30个学生的单科成绩,输出高于平均分的成绩
b.去掉最高分和最低分算平均分
此链接程序设计第1题为a,第5题为b,点击目录可直接跳转
c.编写函数计算sinx的值,精度10^(-6)。

#include<stdio.h>
#include<math.h>
double sin(double x);
int main()
{
    double x;//此处x为弧度制
	scanf("%lf",&x);
	printf("sin%lf=%lf",x,sin(x));
	return 0;
}

double sin(double x)
{
	int i=1,t=1;
	double item=x,sum=0;
	for(i=0;fabs(item)>=1e-6;i++)
	{
		sum+=item;
		t=-t;
		item=t*item*x*x/(2*i+2)/(2*i+3);
	}
	return sum;
}

6、一维数组最值问题、排序、查找

最值问题:
函数功能:数组中最大值和最小值交换位置。

#include<stdio.h>
int main()
{
	int a[10]={1,9,6,2,0,4,8,7,3,5},i,temp;
	int max=0,min=0;
	for(i=0;i<10;i++)
	{
		if(a[i]>a[max])max=i;
	    if(a[i]<a[min])min=i;
	}//此函数也可实现找到最大值和最小值的下标的功能

	temp=a[min];
	a[min]=a[max];
	a[max]=temp;

	for(i=0;i<10;i++) printf("%d ",a[i]);
	return 0;
}

排序:冒泡排序、选择排序、插入排序
此链接程序设计第6题:三种排序方法
查找:顺序查找、二分查找
顺序查找:if(a[i]==n),输出i即可
二分查找:以下程序先将数据排序再进行二分查找:

#include <stdio.h>
int main()
{
	int score[10],i,j,temp;
	int low=0,high=9,mid,t,flag=0;//t为需要查找的成绩
	printf("please input 10 students' score:\n");
	for(i=0;i<10;i++)
		scanf("%d",&score[i]);

	for(i=0;i<9;i++)//冒泡排序需要循环n*(n-1)/2次
		for(j=0;j<9-i;j++)
			if(score[j]>score[j+1])
			{
				temp=score[j];
				score[j]=score[j+1];
				score[j+1]=temp;
			}

	for(i=0;i<10;i++)
	{
		printf("%-4d",score[i]);
	}
	printf("\n");

	printf("input the score you want:");//二分法查找元素
	scanf("%d",&t);
	while(low<=high)
	{
		mid=(low+high)/2;
		if(t==score[mid])
		{
			flag=1;
			break;
		}
		if(t>score[mid]) low=mid+1;
		else high=mid-1;
	}

	if(flag==1)
		printf("%d在第%d的位置上",t,mid+1);
	else printf("not exist");
	return 0;
}

杨辉三角

#include <stdio.h>

int main() 
{
	int i,j,k,pa[100]={1};
	scanf("%d",&k);
	printf("%5d\n",pa[0]);
	for(i=1;i<k;i++)
	{
		pa[i]=1;
		for(j=i-1;j>0;j--)
			pa[j]=pa[j]+pa[j-1];
		for(j=0;j<=i;j++)
			printf("%5d",pa[j]);
		printf("\n");
	}
    return 0;
}

7、二维数组的生成、打印和矩阵转置

a.函数功能:输入一个3*4的矩阵,输出该矩阵和转置矩阵

#include<stdio.h>
int main()
{
	int a[3][4];
	int i,j;
	for(i=0;i<3;i++)
	{
		for(j=0;j<4;j++)
			scanf("%d",&a[i][j]);
	}//输入矩阵

	for(i=0;i<3;i++)
	{
		for(j=0;j<4;j++)
			printf("%d ",a[i][j]);
		printf("\n");
	}//输出矩阵

	for(i=0;i<4;i++)
	{
		for(j=0;j<3;j++)//b[i][j]=a[j][i];
			printf("%d ",a[j][i]);
		printf("\n");
	}
	return 0;
}

b.求矩阵中的最大值以及其在数组中的位置的所有下标。

#include<stdio.h>
int main()
{
	int a[3][3]={1,9,9,6,1,2,1,1};
	int row=0,colume=0,i,j;
	for(i=0;i<3;i++)
	{
		for(j=0;j<3;j++)
		if(a[i][j]>a[row][colume])
		{
			row=i;
			colume=j;
		}
	}//找到第一个最大值的行与列

	for(i=0;i<3;i++)
	{
		for(j=0;j<3;j++)
		if(a[i][j]==a[row][colume])printf("row:%d,colume:%d\n",i+1,j+1);
	}
	return 0;
}

c(选看).输出一个n阶的螺旋矩阵(顺时针,规定n<10)
程序设计思路:将螺旋矩阵的一周分为上、下、左、右四个部分,用4个循环分别赋值。

#include<stdio.h>
void f(int a[10][10],int n,int j);
int main()
{
	int i,j,n;
	int a[10][10];
	scanf("%d",&n);//阶数
	i=(n+1)/2;//从外到里一共i层

	for(j=0;j<i;j++)
	   f(a,n,j);//用于给第j层赋值的函数

	for(i=0;i<n;i++)
	{
		for(j=0;j<n;j++)
			printf("%-5d ",a[i][j]);
		printf("\n");
	}
	return 0;
}

void f(int a[10][10],int n,int j)
{
	int i,k,m;
	m=4*j*n-4*j*j+1;//第j层最左上角元素
	for(k=j;k<n-j;k++)
		a[j][k]=m+k-j;//上层
	for(i=j+1;i<n-j;i++)
		a[i][n-1-j]=a[i-1][n-1-j]+1;//右边
	for(k=n-2-j;k>=j;k--)
		a[n-1-j][k]=a[n-1-j][k+1]+1;//下层
	for(i=n-2-j;i>j;i--)
		a[i][j]=a[i+1][j]+1;//左边
}

8、字符串相关

(1)用数组或指针处理字符串

a.判断字符串是否为回文字符串
利用数组判断:此链接程序设计第12题
利用指针判断:此链接程序设计第2题
b.统计字符串中单词的个数
程序设计思路:
1、用一维字符数组存放字符串;
2、遇到空格表示单词结束,非空格单词没拼完。

#include<stdio.h>
#include<string.h>
int main()
{
	char str[100];
	int i,n,word=1;
	gets(str);
	n=strlen(str);
	for(i=0;i<n;i++)
		if(str[i]==' ')word+=1;
	printf("%d",word);
	return 0;
}

c.人名按照首字母排序
此链接程序设计第9题

(2)字符大小写转换

a.函数功能:将字符串中的大写字母转变为对应小写字母并输出
大小写字母的对应关系:‘a’-‘A’=32。

#include<stdio.h>
#include<string.h>
int main()
{
	char str[100];
	int i;
	gets(str);
	for(i=0;i<100;i++)
		if(str[i]>='A'&&str[i]<='Z') str[i]=str[i]+32;
	puts(str);
	return 0;
}

b.函数功能:将字符串中前三个小写字母改为大写字母并输出。

#include<stdio.h>
#include<string.h>
int main()
{
	char str1[20]={"xUjUNsHUO"},str2[20],*p=str2;
	int i;
	for(i=0;i<20;i++)
		if(str1[i]>='a'&&str1[i]<='z') *(p++)=str1[i]-32;

	for(i=0;i<3;i++)
		printf("%c",str2[i]);
	return 0;
}

(3)字符串连接

函数功能:将两个字符串按字典顺序排序,合并为一个新的字符串并删除该字符串中相邻位重复出现的字符。

#include<stdio.h>
#include<string.h>
void sort(char a[]);//排序
void merge(char *a,char *b,char *c);//将a、b整合并复制到c中
int main()
{
	char a[50]="xujunshuo",b[50]="xiongmao",str[50]={0},*c=str;
	/*要对str初始化,否则会输出很多个烫字大家可以试一试hhh*/
	sort(a);
	sort(b);
	merge(a,b,c);
	puts(str);
	return 0;
}

void sort(char a[])
{
	int i,j,n;
	char t;
	n=strlen(a);
	for(i=0;i<n-1;i++)
		for(j=i+1;j<n;j++)
			if(a[i]>a[j]){t=a[i];a[i]=a[j];a[j]=t;}
}

void merge(char *a,char *b,char *c)
{
	int i,n;
	strcat(a,b);//将字符串b接在a后面,返回a的首地址
	n=strlen(a);
	for(i=0;i<n;i++)
		if(a[i]!=a[i+1]) *c++=a[i];
}

(4)统计子串的个数和位置

a.函数功能:正向和反向搜索子串

#include <stdio.h>
#include <string.h>
void forwardSearch(char *str, char *sub_str);//正向查找函数
void reverseSearch(char *str, char *sub_str);//反向查找

int main() 
{
	char str[200]={"There is no dreams in the waves,only monsters,and the monsters are my only friend"}char sub_str[100];
    printf("请输入要搜索的子串:");
    scanf("%s",sub_str);
    forwardSearch(str,sub_str);
    reverseSearch(str,sub_str);
    return 0;
}

void forwardSearch(char *str,char *sub_str) 
{
    int len1=strlen(str),len2=strlen(sub_str);
    int i,j;
    for(i=0;i<=len1;i++) 
	{
        for (j=0;j<len2;j++) 
            if (str[i+j]!=sub_str[j])break;
        if (j==len2) 
            printf("正向搜索:子串在字符串中出现在位置 %d\n",i);
    }
}

void reverseSearch(char *str,char *sub_str) 
{
    int len1=strlen(str),len2=strlen(sub_str);
    int i,j;
    for (i=len1-len2;i>=0;i--)
	{
        for (j=0;j<len2;j++)
            if (str[i+j]!=sub_str[j]) break;
        if (j==len2)
            printf("反向搜索:子串在字符串中出现在位置 %d\n",i);
    }
}

b.函数功能:查找字符串中出现某单词的个数和位置并替换该单词

#include <stdio.h>
#include <string.h>
int find_replace(char a[],char b[],char c[]);

int main()
{
	char str[100]={"this is a test program and a test data."};
	char substr1[10]="test",substr2[10]="actual";
	int n;
	n=find_replace(str,substr1,substr2);
	printf("%d\n",n);
	puts(str);
	return 0;
}

int find_replace(char a[],char b[],char c[])
{
	int i,j,k,count=0;
	char temp[100];
	for(i=0;a[i]!='\0';i++)
	{
		j=i;k=0;
		while(a[j]==b[k]&&b[k]!='\0'){j++;k++;}//找相同字符串
		if(b[k]=='\0')//a遇到空格时b输入完整则计数并交换
		{
			count++;
			strcpy(temp,&a[j]);//所替换单词后的字符串先不动
			strcpy(&a[i],c);//替换
			i=i+strlen(c);//为下一次循环准备
			strcat(a,temp);//将不动的部分接在后面
		}
	}
	return count;
}
Logo

欢迎加入我们的广州开发者社区,与优秀的开发者共同成长!

更多推荐