- 注意printf的输出格式:%d %o %x
- 不要轻易在scanf中加换行符 scanf(“%d\n”) 按回车输入不了
- f六位小数 不足补零
- m指定输出宽度 小数点也战一位
- .n输出n位小数
- 0~127的范围内,整数和char可以通用
- “A”:65 “Z”:90
-“a”:97 “z”:122 - getchar() 读入一个字符 反之是putchar(ch)
getchar()会接收回车符,ASCll为10 需要多用一个getchar将其吸收 - 数字字符转换数字 c-‘0’
数字转换成数字字符 c+‘0’
大转小 ch+32 或 ch-‘A’+a - 循环读入多行字符:(c=getchar() != EOF)
- 数组只能在声明的同时初始化 分开写不对
- 字符串的最后一个字符:空字符(“\0”)ASSll: 0
空白符(空格符):32、水平制表符:9、回车符:13 - 字符串输出:printf(“%s”,str)、puts(str)
- 字符串输入:scanf(遇到空格符结束,可以输入多个参数)、gets(可以读取空格,遇到换行符结束,只能输入一个参数)、fgets(str, strlen, 文件指针) != NULL,文件指针处改为stdin从键盘输入
- fscanf:从文件输入而不是键盘 fprintf:输出到文件而不是屏幕(txt文件操作)
相比起scanf和printf只多了第一个参数,传入文件指针表示对什么文件进行操作
#include<stdio.h>
#include<stdlib.h>
//键盘输入存储学生信息到txt文件
int main() {
char stuid[10], name[20];
float score;
FILE* fp;
if ((fp = fopen("E:\\score.txt", "w")) == NULL) {
exit(0);
printf("文件打开失败!");
}
fprintf(fp, "学号\t姓名\t入学成绩\n");
for (int i = 0; i < 2; i++) {
printf("请输入学生学号姓名和入学成绩(空格隔开):");
scanf("%s%s%f", &stuid, &name, &score);//键盘到文件
//注意此处输出格式要用\t \n来调整格式
fprintf(fp, "%s\t%s\t%f\n", stuid, name, score);//输出到文件
}
fclose(fp);
}
删掉第一行的中文后读取
while (fscanf(output, "%s%s%f", &stuid, &name, &score) != EOF) {
printf("%s\t%s\t%\n", stuid, name, score);
}
四、运算符和表达式
1、优先级:
- 常用优先级(大到小):自增++ 、大于 、 !=、&& 、|| 、条件三目 、+= 、逗号。同等地位则左结合(除了自增三元赋值)
- 1 || 0 && 0 --> &&的优先级比||高 等价于 1 || ( 0 && 0 ) 1已经为真 ||短路右边不执行 答:1
- 0 && 0 || 1 等价于 ( 0 && 0 ) || 1, ||前部分为0 但不出现短路,最后值为1.而不是&&短路。 总结:当&&和||同时出现需要先考虑优先级用括号括起,再去考虑短路
- 注意赋值符号导致的变量的值中途改变 如:x=1时、 x += x += x+1的值为6 、和a=b, b=c,c=d和表达式的结合,还有和类型转换截断 (int)3.14 的组合
- a*b\2 从左到右 、a+(b++) 的括号可有可无,都是先进行加法后再自增
- char必须转换成int,‘a’+‘b’=195,同时注意float的六位小数位
- (double)a/2 先执行类型转换
int x,y;
printf("%d", 0 || 8!=5 && 8 );
//优先级:!= > && > ||
0 || ((8!=5) && 8) --> 0 || (1 && 8) --> 1
int x,y;
printf("%d", (x = 1, y = 2, x++, y++, x + y));//5 逗号表达式优先级最低
//故要等所有都执行完才执行逗号表达式,相当于从头到尾都执行了一遍
int x=0,y=0;
printf("%d", x += 1 != x > y);
//x = x + (1 != (x > y))
// x = x+ (1 != 0)
// x = x+1
// x=1
//优先级:大于小于 > != > 赋值+=
2、逗号表达式:
int x = 0, y = 0,z=0;
(x, y, z) = (1, 2, 3);//相当于两个逗号表达式,等价z=3
printf("%d、%d、%d", x, y, z);//0 0 3只有z赋到了值
x=(x, y, z) = (1, 2, 3);//把z的值3赋给了x
printf("%d、%d、%d", x,y,z);//3 0 3
int x = 0, y = 0,z=0;
(x, y, z = 1, 2, 3);//把z的值3赋给了x
//先执行z=1,由于没有赋值,逗号表达式的结果3没有保存
printf("%d、%d、%d\n", x, y, z);//0 0 1
x = (x, y, z = 1, 2, 3);
printf("%d、%d、%d\n", x, y, z);//3 0 1
x = 0, y = 0, z = 0;
//逗号表达式的值为3-0 然后才赋值给3,而不是逗号表达式里为x赋值3
x = (x, y, z= 1, 2,3) -x;
printf("%d、%d、%d\n", x, y, z);//3 0 1
五. 分支结构
- 海伦公式:由三角形边长a、b、c, 半周长h 得面积S=sqrt( h*(h-a)*(h-b)*(h-c) )
- 椭圆公式、平闰年(%100!=0)、构成三角形的条件
- else一定要和最近的if配对 (找错)
六、循环结构程序基本算法
1、课本例题
1-1、判断一个数是否为素数
//此方法判断输入的数是否是素数
int flag(int n) {
int i, k;
k = sqrt(n);//对输入的数开根号
for (i = 2; i <= k; i++) {
if (n % i == 0) {
break;
}
}
if (i>k){//排除i=k的的情况
return 1;
}else{
return 0;
}
}
1- 2、数列求和
//计算1/2 + 3/2 + 5/3 + 8/5 +...
int main(){
int sum,t,x=1,y=2;
for (int i = 1; i < 10; i++) {
sum += i;
t = x; x = x + y; y = x;//前一个的分母是下一个的分子,前一个的分子+分母是下一个的分母
}
}
1-3、三角形打印
1-4、一维数组杨辉三角(不会)
#include<stdio.h>
#define N 6
/*
1、一维数组打印杨辉三角
*/
void one() {
int a[N + 1], i, j;
a[1] = 1;
printf("%d\n", a[1]);
for (i = 2; i <= N; i++) {
a[i] = 1;
//计算第二行开始的除了两端的数字
for (j = i - 1; j >= 2; j--) {//第三行才进入
//1 1
//1 2 1 2来自其上一次执行的同样位置的元素和其之前元素之和
a[j] = a[j] + a[j - 1];
}
//每计算一行数据打印一行 <i:需要多少打印多少
for (j = 1; j < i; j++) {
printf("%d ", a[j]);
}
printf("\n");
}
}
int main(){
one();
}
1-5、牛顿迭代法(不会)
牛顿迭代法计算x平方=a的解,即计算根号a的值
x = 1 +( a - 1 ) / ( x + 1 )
1-6、文本文件字符统计(重点)
- 一个个字符读取的方式,统计出现次数用数组
int main(){
FILE* fp;
char ch, count[128];
while (ch = (fgetc(fp)) != EOF) {
count[ch]++; //对应位置自增
}
}
2、课后习题
2-1、程序阅读题
#include <stdio.h>
int main()(
char str[20]="azdwgtjqmn";
int i,count=0;
for (i=0; str[i]!='\0'; i++){
str[i]+=4;
if (str[i]>'z') str[i]-=26;
count++;
}
printf("str[%d]=%s\n", count, str);
return 0;
}
注意阿斯克码对应得字母全写成小写,Q写q 全部列出来
2-2、程序填空题
(1) 打印上下三角形
(2) 冒泡变形
while (i <= N)
printf("%d, ",/*第4个空*/ a[i++]);
使用i++避免死循环,用for则不需要,但while打印图形的代码更加简洁
2-4(6)同构数
#include<stdio.h>
//找出同构数 6->36 25->625
//同时取两者的个位,依次比较,当两者比较完后,如果较小的数能除尽说明是同构
int main() {
int i, j, t, k;
for (int i = 1; i <= 1000; i++) {
t = i;
k = i * i;
while (t) {
if (k % 10 != t % 10) break;
else {
k = k / 10;
t = t / 10;
}
}
if (t == 0) {
printf("%d %d\n", i, i * i);
}
}
}
七、函数与结构化程序设计
1、课本例题
1-1、求组合数(公式重要)
//计算n的阶乘
long factorial(int n) {
int i;
long s = 1;
for (i = 1; i <= n; i++) {
s = s * i;
}
return s;
}
本质是三个阶乘的乘除 ,将共性抽取,大的n在上面 下的k在下面做分母,位置互换
1-2、判断素数方法
#include <math.h>
int prime(int n) {
int num,flag=1;
if (n == 1) {
return 0;
}
num = sqrt(n);
for (int i = 2; i < num; i++) {
if (num % i == 0) {//不是素数
flag=0;
break;//找到了就退出
}
}
return flag;
}
程序最好只有一个出口,不要设置多个return
int fun(float x,float,y){
return (x*y);
}
注意此时返回的值要转换成int
值传递:实参赋值给形参 ,但不会影响各自的值,互相独立,形参值改变,主函数实参不变
1-3、两个正整数的最大公约数(方法重要)
#include <stdio.h>
int div(int a,int b ) {
int r, t;
if (a < b) t = a, a = b, b = t;
if (b > 0) {//保证被除数大于零
while ((r = a % b) != 0) {
a = b, b = r;//上一次的结果成为被除数
}
}
}
1-4、随机数(方法重要)
#include <stdio.h>
#include<random>
//产生[low,high]之间的随机数
int random(int low,int high ) {
int k = rand() % (high - low + 1);//[0,high-low]
return low + k;//[low,high]
}
1-5、递归调用过程(思想重要)
#include <stdio.h>
void fun1(int n) {
if (n >= 10) {
fun1(n / 10);//先逐级调用,再回代过程中才顺序执行打印语句
}
printf("%d, ", n%10);
}
void fun2(int n) {
printf("%d, ", n % 10);//调用之前就打印了,和回代无关
if (n >= 10) {
fun2(n / 10);
}
}
int main() {
fun1(567);
printf("\n");
fun2(567);
}
函数调用结束返回的时候,要注意返回哪一层
如果函数递归了,相当于阻塞了其之后下面的代码。要等其调用完之后,才从当前结果逐层返回回去
1-6、递归 实现斐波那契数列(重要)
#include <stdio.h>
//1 1 2 3 5 8.. 第三项开始是前两项之和
long Fibo(int n) {
long value;
if (n == 1 || n == 2) //1、2项都等于1
value = 1;
else
value = Fibo(n - 1) + Fibo(n - 2);//第三项为 f(1) + f(2) = 2
//注意是n-2和n-1
return value;
}
1-7、递归 求一维数组最大值==(重要)==
#include <stdio.h>
//a={1,2,3,4} 3 a数组中前n项的最大值
int max(int a[],int n) {
int value;
//递归到最后把数组初值给了value
if (n == 0) value = a[0];
else {
value = max(a, n - 1);//卡住,当n=1时才进行会回代执行下面代码
//n依次为1 2 3
if (a[n] > value) {
value = a[n];
}
}
}
1-8、宏定义的形式参数运算
#define L(a,b,c) a+b+c
x=6*L(3,4,5) // 成了6*3+4+5 要在宏定义处加括号此处才会有括号
2、课后习题
2-1、最大公约数和最小公倍数 (记住)
- 最大公约数:辗转相除法,余数做下一次的除数(根号后面的数)
- 最小公倍数 = 两数乘积 / 最大公约数
#include <stdio.h>
int max(int a,int b) {
//保证传入的a是两数大的一方
int r,t;
if (a < b) {
t = a; a = b; b = t;
}
//除数大于0才除
if (b > 0) {
while ((r = a % b) != 0) {
//除数变成被除数,余数变成下一次的除数
a = b; b = r;
}
}
}
//最小公倍数 = 两数乘积 / 最大公约数
int min(int a, int b) {
int x;
x = a * b / max(a, b);
}
2-2、最大素数因子
- 质数(素数):只能被1和其本身相除的数 但1何其本身不是素数
#include <stdio.h>
#include<math.h>
//判断质数(素数):只能被1和其本身相除的数 但1何其本身不是素数
int isNum(int n) {
int m = sqrt(n);
for (int j = 2; j <= m; j++)
{
if (n % j == 0)
{
return 0;
}
}
return 1;
}
int main() {
int num, max=0, count = 0;
printf("请输入一个正整数:");
scanf("%d", &num);
for (int i = 1; i <= num; i++)
{
if (num % i == 0)//最大质数能整除
{
if (isNum(i))
{
if (i>max) {
max = i;
}
}
}
}
printf("最大的素数因子是:%d", max);
return 0;
}
2-3、递归-求整数幂 (不会)
#include <stdio.h>
int power(int n, int d) {
if (d == 0) {
return 1;
}
return n*power(n, d - 1);
}
// n*
// n*n*
// n*n*n*
// n*n*n*1
// 把大问题拆分成小问题,把小问题拼接成大问题,确定终止条件
int main() {
int num =power(3, 3);
printf("%d", num);
}
2-4、递归-求两数最大公约数 (不会)
- 公约数就是公因数 辗转相除法
#include <stdio.h>
int max(int m, int n) {
if (n == 0) return m;
//不断处理除数和被除数,直到被除数为0,返回上一次的除数
//如48 ÷ 36 = 1...12
//36 ÷ 12 = 0 12是最大除数
return max(n, m % n);
}
2-5、递归-返回指定数字 (不会)
- 编写递归函数 digt(n,j),它返回整数n从右边开始的第j位数字。例如:
digit(25364,4)=5
digit(25634,3)=6
#include <stdio.h>
int digit(int n, int j) {
if (j == 1) {
return n % 10;
}
return digit(n / 10, j-1);
}
int main() {
int num = digit(25634,4);
printf("%d", num);
}
递归方法总结
1、将问题拆解,如求幂拆解成n*n, 斐波那契是(n-1,n-2),公约数是将除数变成余数,被除数变成除数
2、拆解的小问题是递归传值的参数,如公约数是每次都要传入,而幂是进行×n运算
3、确认最后的终止条件,幂函数是次方为0了就停了,公约数是余数为0就停
八、指针与数组
1、课本例题
1-1、固定格式文本文件读取(以fgetc(fp)的形式)(重要)
- 172200100;Lin Daihua;128;116;82;275;172200101;Lai Baichi;100;126;92;285;172200102;Wu Jiaxu;168;126;92;255;
#include <stdio.h>
#include<stdlib.h>
FILE* fp;
//此方法用于一个个字符串读取,当符合条件存入字符数组中,以;作为单位读取
//比起scanf更容易操作但代码量稍多
int read_flag(char* p) {
//从文件中读取一个字符
char ch = fgetc(fp);
while (ch == ' ' || ch == '\t' || ch == '\n') {
ch = fgetc(fp);//自动读取下一位 实现跳过空白符的作用
}
while (ch != EOF && ch != ';') {
*p++ = ch;//存储进空字符串中
ch = fgetc(fp);
}
*p = '\0';//形成字符串
if (ch == EOF) return 0;//代表文件已经读到尾部了
else return 1;//还有下个学生可以读
}
int main() {
char str[30];
float sum, score, maxsum;
int order=0; //记录当前读取的是第几个属性值
if ((fp = fopen("D:\\score.txt", "r")) == NULL) {
printf("打开文件失败!");
exit(0);
}
sum = 0.0, maxsum = 0.0;
while (read_flag(str) ){
if (order % 6 <= 1) {//姓名学号
printf("%s ", str);
}
else if (order % 6 <= 5) {//四门成绩
score = atof(str);//将字符串转换成浮点数
sum += score;
printf("%.2f ", sum);
if (order % 6 == 5) {
printf("%.f\n", sum);
if (sum > maxsum)maxsum = sum;
sum = 0.0;
}
}
order++;
}
}
补充:fscanf通配符方式读取 (重要!!)
- % [^; ] 读取到;为止,不包括;
- %[^1-9A-Z] 读取到1-9和A-Z后才终止存储到对应变量中,可以用来屏蔽中间的空格
int main(int argc,char *argv[]) {
char buf[100],name[20];
int id,age,s1,s2,s3,s4;
FILE* fp;
fp = fopen("D:\\score.txt", "r");
//172200100; Lin Daihua; 128; 116; 82; 275;
while (fscanf(fp, "%d;%[^;];%d;%d;%d;%d;",&id,&name,&s1,&s2,&s3,&s4) != EOF) {
printf("%d、%s、%d、%d、%d、%d\n", id, name, s1, s2, s3, s4);
}
/*
读取格式:172200100;Lin Daihua;128;
通配符: %d ; %[^;] ; %d;
*/
//% [^; ] 读取到;为止,不包括;
//%[^1-9A-Z] 读取到1~9和A~Z后终止
}
1-2、二维数组打印杨辉三角
#include <stdio.h>
int main() {
int a[5][5],i,j;
//先打印每行的开头和结尾的1
for (i = 0; i < 5; i++){
a[i][0] = a[i][i] = 1;
}
//从第三行开始打印内部元素 注意起点
for (i = 2; i < 5; i++) {
for (j = 1; j < i; j++) {
a[i][j] = a[i-1][j]+a[i-1][j-1];
}
}
for (i = 0; i < 5; i++) {
for (j = 0; j <= i; j++) {
printf("%d ", a[i][j]);
}
printf("\n");
}
}
1-3、行指针,元素指针,元素间的关系 (重要)
- 二维数组名a 默认是行指针(一维数组数组名是元素指针)
- 做加减法时,当a是行指针时,a+1时候默认跳过一行,而不是一个元素。
- 第k个元素的元素指针都是和列进行除法和取余运算
- a【0】是一维数组数组名,即首元素地址,元素指针,&a【i】才是行指针
- *a是行指针解引用,取出的是元素指针
- 加法和【】的替换 如:((a+i)+j)~a[i][j]
(a[0]+iN+j)的N是列
1-4、字符串处理函数 (特别重要!)
- 求字符串长度strlen(str):遇到‘\0’就终止,其不包括在长度内
#include <stdio.h>
#include<string.h>
int main() {
char str[20] = "\t\v\\\0will\n"; //3 t v \
char str2[30] = "\x68\082\n"; //1 x68 十六位进制数 \1\2\3长度为3
printf("%d、%d", strlen(str), strlen(str2));
}
- 字符串拼接 strcat(str1,str2):将2拼接到1的末尾.
必须保证str1的容量足够大,拼接前都有\0,拼接后只有一个\0 - ==字符串赋值 strcpy(str1,str2),将2中的复制到1中去,调用成功返回str1的起始地址 ==
strncpy: 在原有基础上多加了个n,可指定赋值前几位字符,但需要手动添加’\0’
#include <stdio.h>
#include<string.h>
int main() {
char str1[20] = "星期一";
char str2[30] = "星期六";
strcpy(str1, str2); //成功返回str1的起始地址
puts(str1);//星期六
//字符串的赋值不能用 str1 = str2,因为常量不可修改
//只能通过strcpy进行覆盖
strncpy(str1, "Sunday", 3);//将Sun赋给str1
str1[3] = '\0';//手动添加结束符
puts(str1);
}
- 字符串比较 strcmp(str1,str2)
将两个字符串自左至右逐个字符比较(根据ASCII码大小)直到出现不同字符或遇到‘\0’
str1=str2 0
srr1>str2 正数 反之负数,换句话说就是strcmp(str1,str2)>0 说明前面的数字大
字符串的比较不能用”==“ 比的是地址
字符串的赋值和比较要用方法
1-5、指针找错
- 注意在循环中对指针进行操作,要将移动到末尾的指针要重新移动回首地址
- 实参和形参是指针时,形参会间接影响实际的变量值,但还是值传递。同时注意其他形参都不能改变实际的值,只有传的是指针才可以。
- 指针作为函数的实参,要传的是地址,注意加取地址符
1-6、将两个升序数组合并成一个
#include <stdio.h>
//传入两个升序数组合并成一个新数组z
void merge_sort(int* x, int lenx, int*y,int leny,int *z) {
int i, j, k;
//将xy两个数组逐个元素进行比较
while (i < lenx && j<leny) {
if (x[i] < y[j]) {
z[k++] = x[i++];
}
else {
z[k++] = x[j++];
}
}
//把剩余元素全部存入余下的数组z中
while (i < lenx) {
z[k++] = x[i++];
}
while (j < leny) {
z[k++] = x[j++];
}
}
1-7、实现strcmp的功能
int strcmp02(char* ch1, char* ch2) {
while (ch1 && ch2 ) {
if (*ch1 == *ch2) {
ch1++;
ch2++;
}
else {
break;
}
}
return (*ch1 - *ch2);
}
1-8、字符串匹配
- 核心:用下标,母串每次比较完成一次后移动一位,子串置空
- 补充1:strstr(str, substr):返回第一次出现子串的地址
- 补充2:strchr(str,ch) 返回字符ch第一次出现的地址
#include <stdio.h>
#include<string.h>
//找出子串在母串第一次出现的位置
int index(char*s, char*t,int start) {
int m, n,i,j;
m = strlen(s);
n = strlen(t);
if (start < 0 || n==0) {
return -1;
}
while (i<m && j<n) {
if (s[i] == t[j]) { i++; j++; }
//核心代码,母串移动一位,子串置空
else { i = i - j + 1; j = 0; }
}
//如果比较的长度等于子串长度
if (j == n) return i - n;//返回位置
else return -1;
}
1-7、二维数组做参数
//此时的实参为两个一维数组数组名
int fun1(int x[],int y[]) {} //等价于int *x,int *y
//此时实参为二维数组名+0(行指针),一维数组数组名(元素指针)
int fun2(int (*x)[3], int *y) {} //等价于int x[][3],int y[]
//注意使用的时候需要将x解引用得到元素指针,
//在做加法得到每个元素指针再解引用得到每个元素
1-8、返回指针的函数
- 如果返回的指针是指向那个函数中的变量,则可能会出错,如下:
//此时的实参为两个一维数组数组名
int* max(int *p) {
int m = *p; return &m; //指向max函数中声明的变量,可能出错
int* q = p; return q; //要用指针存储形参指针而不是变量
}
1-9、字符串数组的排序
- 运用指针数组 char *arr[] = {“str1”, “str2”, “str3”…};实现对字符串数组的排序 ,其还有另一种写法**p。存储指针的数据,每个指针指向一个字符串,然后用选择排序(第0个字符和第1,2,3个比较,以此类推选出最小),注意比较要用strcmp逐个字符比较
1-10、main函数的形参及文件复制(逐个复制方法重要!
#include <stdio.h>
/*
输入格式:命令名 参数1 参数2...
例如:输入COPY C:\old.txt D:\new.txt
argc获得整数值3 代表有三个数
argv[0]=COPY、argv[1]=C:\old.txt、argv[2]=C:\new.txt
*/
int main(int argc,char *argv[]) {
FILE* fp1, * fp2;
char ch;
if (argc != 3) {//说明格式不对
printf("格式:cp 源文件名 目标文件名");
}
fp1 = fopen(argv[1], "r");//源文件读
fp2 = fopen(argv[2], "w");//目标文件写出
while ((ch = fgetc(fp1)) != NULL) {//逐个读取源文件字符
putc(ch,fp2);//每读取一个写出一个
}
}
2、课后习题
2-1、行指针的写法 (错了
)
#include<string.h>
int main() {
char str[20], s[3][20];
for (int i = 0; i < 3; i++) {
gets(s+i);
gets(&s[i]);
//要填行指针,而不是s[i][20]
}
}
2-2、子母串比较的另一种形式(错了
)
#include <stdio.h>
int at(char* substr, char* str) {
int i, j, post;
//通过引入新的变量post实现母串的自增
//post没使用过要想到怎么使用
for (post = 0; str[post] != '\0'; post++)
{
//母串每次自增到下一位
i = 0; j = /*第2空*/post;
while (substr[i] != '\0' && substr[i] == str[j])
{
i++;
j++;
}
if (substr[i] == '\0')
{
return /*第3空*/post + 1;//下标从0开始,正常序号要+1
}
}
return 0;
}
2-3、结构体实现学生排序
- 先按照第一门成绩排,再按照第二门排,最后按照学号排
#include<stdio.h>
#define N 6
struct stu {
int id;
int scores[4];
}s[6];
int main() {
FILE* fp;
fp = fopen("D://score.txt", "r");
stu t;
int i, j, k;
//读取文件数据进结构体数组中
for (i = 0; i < N; i++) {
fscanf(fp, "%d %d %d %d %d", &s[i].id, &s[i].scores[0], &s[i].scores[1], &s[i].scores[2], &s[i].scores[3]);
}
printf("排序前:\n");
for (i = 0; i < N; i++) {
printf("%d %d %d %d %d\n", s[i].id, s[i].scores[0], s[i].scores[1], s[i].scores[2], s[i].scores[3]);
}
for (i = 0; i < N; i++) {
k = i;
for (j = i+1; j < N; j++) {
if (s[j].scores[0] > s[k].scores[0]) {
k = j;//记录第一门课成绩最大的学生
}
else if (s[j].scores[0] == s[k].scores[0]) {//第一门课相等
if (s[j].scores[1] > s[k].scores[1]) {
k = j;//更改k值记录第二门课最大的学生
}
else if (s[j].scores[1] == s[k].scores[1]) {//第二门课相等
if (s[j].id < s[i].id) {//学号小的在前面
k = j;//更改k值记录学号最大的学生
}
}
}
}
//交换两个学生
if (k!= i) {
t = s[i]; s[i] = s[k]; s[k] = t;
}
}
printf("排序后:\n");
for (int i = 0; i < N; i++) {
printf("%d %d %d %d %d\n", s[i].id, s[i].scores[0], s[i].scores[1], s[i].scores[2], s[i].scores[3]);
}
}
掌握选择排序 循环i之后的元素,每次找出最大就交换
2-4、二维数组的鞍点
- 重点再倒数第二个if,代表第二个for顺利比较完成,没有发生值的交换
#include<stdio.h>
int main()
{
int i, j;
int arr[3][3] = { 0 };
int max = 0;
int flag = 0;//如果找到了鞍点给它赋值 1
int arr[3][3] = { 1,2,3,4,5,6,7,8,9 };
//找鞍点
for (i = 0; i < 3; i++)
{
//让max等于二维数组第 i 行的第一个元素
max = arr[i][0];
//记录最大值所在的列
int t = 0;
//找出一行中的最大值并把值赋给 max
for (j = 1; j < 3; j++)
{
if (arr[i][j] > max)
{
max = arr[i][j];
t = j;
}
}
//判断 max 是否为该列上最小的元素
for (j = 0; j < 3; j++)
{
//上边的 t 记录了 max 所在的列
//所以用 max 与该列的元素比较,看 max 是否为该列上最小的元素
if (max > arr[j][t])
{
//如果大于就跳出
break;
}
}
//如果全部比较完(也就是j==3的时候)说明 max 为当列最小,max为鞍点
if (j == 3)
{
printf("找到了鞍点在:%d行%d列,为%d\n", i, j, arr[i][t]);
flag = 1;
break;//因为只有一个鞍点,所以找到了就退出循环
}
}
if (flag != 1)
{
printf("没有找到鞍点 \n");
}
return 0;
}
十进制转十六进制
#include <stdio.h>
void func(int n, char buf[])
{
if (n < 16)//n==0
printf("0x");
else
func(n / 16, buf); //递归运算
printf("%c", buf[n % 16]); //查字库输出对应的字符
}
int main()
{
int n;
char buf[17] = "0123456789ABCDEF"; //创建十六进制字库
printf("输入一个十进制正整数:");
scanf("%d", &n);
printf("转换成十六进制:");
func(n, buf); //调用递归函数来转换成十六进制输出
return 0;
}
模考卷
第一套
编程题
一、删除后按原次序组成最小
- 请在整数 n=742683613984 中删除 8 个数字, 使得余下的数字按原次序组成 的新数最小。
#include<stdio.h>
#include<string.h>
int main(){
int i, j, t, flag;
char a[30] = "43612", c;
t = strlen(a);
while (strlen(a) > 4)
{
flag = 0;
//获得每个下标
for (i = 0; i < strlen(a) - 1; i++)//7
{
//后面的比前面的数大,不大则继续找下一对
if (a[i] > a[i + 1])//7>4
{
flag = 1;
//从较大数的下标开始,将其之后的元素重新存入数组中
//相当于整个数组左移了一位
for (j = i; j < strlen(a) - 1; j++)
a[j] = a[j + 1];//4268... 替换掉了一开始的最大数7
a[--t] = '\0';//字符数组结束符
}
//标志发生了一次替换
if (flag == 1)
break;
}
//替换完成
if (flag == 0)
break;
}
for (int j = 0; j < 4; j++)
printf("%c", a[j]);
printf("\n");
return 0;
}
/*
转换成字符数组进行操作
找四位数
先从头到尾开始找最小的数 A
两两进行比较,如果后一个数比前一个数还要小,就把整个数组往前移动一位
找四位数,for循环用于每次剔除元素,直到无法提出
注意flag的变化
*/
二、自恋数
- 设计一个程序, 输出 1~99999 的所有自恋数。自恋数:当一个 n 位数的所有数位上数字的 n 次方和等于这个数本身。如 1, 2, 3, …, 9 是自恋数。
#include<stdio.h>
#include<math.h>
/*
设计一个程序, 输出 1~99999 的所有自恋数。
自恋数:当一个 n 位数的所有数位上数字的 n 次方和等于这个数本身。如 1, 2, 3, ..., 9 是自恋数。
*/
//获取位数
int digtal(int n) {
int d = 0;
while (n > 0) {
d++;
n = n / 10;
}
return d;
}
int main(){
int d,i,j,sum=0;
for (i = 1; i < 99999; i++) {
d = digtal(i);
j=i;
while (j > 0) {
//获取所有数位上数字的 n 次方和
sum += pow(j % 10,d);
j = j / 10;
}
if (sum == i) {
printf("%d是自恋数\n", i);
}
d = 0;
sum = 0;
}
}
拓展一:同构数
- 输出 2~1000之间的所有同构数,所谓同构数是指它出现在它的平方数的右端。
例如,5、6、25 的平方分别等于 25、36、625,所以5,6和 25 都是同构数。
#include<stdio.h>
int static sum2 = 0;//注意要是全局变量
int total(int target,int count) {
if (count > 0)
{
递归实现逆序输出 不使用则是顺序输出得52
total(target / 10, count - 1);
sum2 = sum2*10 + target % 10;
}
return sum2;
}
int main() {
int i, j, k, count=0, sum;
for (i = 2; i < 1000; i++)
{
k = i;
while (k > 0) //判断所找的数是一个几位数
{
count++;
k = k / 10;
}
j = i * i;
sum = 0;
//计算同构数
sum = total(j,count);
if (sum == i)
{
printf("%d的平方是%d,%d是同构数!\n", i,j,i);
}
count = 0;
sum2 = 0;
}
return 0;
}
2、等比数
#include<stdio.h>
#include<math.h>
void repeat(int *p,int n) {
for (int a = 0; a < 3; a++)
{
p[n % 10]=1;
n /= 10;
}
}
int allUse(int *q) {
for (int f = 1; f < 10; f++)
{
if (q[f] != 1)
return 0;
}
return 1;
}
int main() {
for (int i = 123; i <= 987; i++)
{
for (int j = 123; j <= 987; j++)
{
for (int k = 123; k < 987; k++)
{
if (i*2 == j && i*3 == k) {
int num[10] = { 0 };
repeat(num, i);
repeat(num, j);
repeat(num, k);
if (allUse(num) == 1)
printf("%d %d %d\n", i, j, k);
}
}
}
}
return 0;
}
三、合并文件信息将其排序
- 有两个磁盘⽂件 A.txt 和 B.txt, 各存放⼀⾏字母, 今要求把这两个⽂件中
的信息合并(按字母顺序排列), 输出到新⽂件 C.txt 中。
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
/*
3、有两个磁盘⽂件 A.txt 和 B.txt, 各存放⼀⾏字母, 今要求把这两个⽂件中
的信息合并(按字母顺序排列), 输出到新⽂件 C.txt 中。
*/
//将如字串含有大小写的字符数组区分大小写进行排序
void sort(char a[], int n) {
int i, j;
char temp;
for (i = 0; i < n - 1; i++) {
for (j = i + 1; j < n; j++) {//确定要比较的数
if (a[i] >= 'A' && a[i] <= 'Z' && a[i] >= 'a' && a[i] <= 'z') {
if (a[i] + 32 > a[j]) {//比较大写字母
temp = a[i];
a[i] = a[j];
a[j] = temp;
}
else if (a[i] - 32 > a[j]) {//比较小写字母
temp = a[i];
a[i] = a[j];
a[j] = temp;
}
else {
if (a[i] > a[j]) {
temp = a[i];
a[i] = a[j];
a[j] = temp;
}
}
}
}
}
}
int main(){
FILE* fp_A, * fp_B, * fp_C;
char str[81];
int i=0;
if ((fp_A = fopen("D:\\A.txt", "r"))==NULL) {
exit(0);
printf("打开文件失败!");
}
if ((fp_B = fopen("D:\\B.txt", "r")) == NULL) {
exit(0);
printf("打开文件失败!");
}
if ((fp_C = fopen("D:\\C.txt", "w")) == NULL) {
exit(0);
printf("打开文件失败!");
}
//一个个字符读入 重要!!!
//fscanf是按格式一行读入,此处要存入字符串,故用一个个存储的方式
while (!feof(fp_A)) {
str[i++] = fgetc(fp_A);
}
while (!feof(fp_B)) {
str[i++] = fgetc(fp_B);
}
int len = strlen(str);
//对数组进行排序
sort(str, len);
for (i = 0; i < len; i++) {
putchar(str[i]);
fputc(str[i],fp_C);
}
fclose(fp_A);
fclose(fp_B);
fclose(fp_C);
}
/*
法一:追加,读取A的内容到数组,再把数组添加到B 再读取B (麻烦)
法二:因为将内容进行排序,分别将A、B都读取到数组中进行排序
数组进行操作时注意大小写的转换
重点关注两个文件的内容读取到一个数组的操作,fgetc(*fp) 和!feof判断
*/