寒假进阶
指针:
1.定义一个swap函数,从主函数中向swap函数传入两个数,通过swap函数实现将两个数据交换的功能,分别输出交换前的数据值和调用swap函数交换后的数据值。
#include<stdio.h>
void swap(int *a,int *b);
int main()
{
int a,b;
scanf("%d %d",&a,&b);
printf("a=%d b=%d\n",a,b);
swap(&a,&b);//传的是地址
printf("a=%d b=%d",a,b);
return 0;
}
void swap(int *a,int *b)
{
int t=*a;
*a=*b;
*b=t;
}
输入:
输出:
知识总结:
- 指针变量:用来保存 指针 的变量。
- int * a (可储存int类型变量的地址),通常int * a=&num(进行赋值),a单独拿出来就是num的地址,*a(解地址)就是num的值
- 特殊情况:数组、函数、字符串作右值不加&
结构体:
2. 定义一个student结构体数组,结构体成员内部包括学生学号,成绩,等内容(可自己添加),完成程序实现学生信息的输入(从键盘输入),保存至结构体数组中并输出(从显示屏输出)。
#include<stdio.h>
struct student{
char name[20];
int xh;
double grade;
};
int main()
{
printf("请输入班级人数:");
int n;
scanf("%d",&n);
struct student stu[n];
int i;
for(i=1;i<=n;i++)
{
printf("请输入第%d个学生姓名 学号 成绩:",i);
scanf("%s%d %lf",stu[i].name,&stu[i].xh,&stu[i].grade);
}
for(i=1;i<=n;i++)
{
printf("%s %d %.1lf\n",stu[i].name,stu[i].xh,stu[i].grade);
}
return 0;
}
输入:
输出:
知识总结:
- 结构体声明,可用typedef,然后结构体定义会相对简单
- 记得声明结尾分号
链表:
3. 定义一个student链表完成第2题的要求,并分别用链表的头插法和尾插法实现。**
先摸索的尾插:
#include<stdio.h>
#include<stdlib.h>
typedef struct _student{
int xh;
double grade;
struct _student * next;
}student;
int main()
{
student * head= NULL ,*p,*last;
int n;
printf("请输入班级人数:");
scanf("%d",&n);
int i;
for(i=1;i<=n;i++)
{
p=(student*)malloc(sizeof(student));//空间是必须开辟滴
printf("请依次输入第%d个学生学号 成绩:",i);
scanf("%d %lf",&p->xh,&p->grade);
p->next=NULL;//确保最后一个永远指向HULL
last=head;//初始 让头和尾在同一位置
if(last!=NULL){//刚开始last为空时,跳到else
while(last->next!=NULL){//当last->next为空时,即last为最后一个结点
last=last->next;
}
last->next=p;//让last的指针指向p
}else{//先让头等于第一个结点
head=p;
}
}
student * q;//输出
for(q=head;q;q=q->next){
printf("%d %.1lf\n",q->xh,q->grade);
}
return 0;
}
输入:
输出:
头插:
#include<stdio.h>
#include<stdlib.h>
typedef struct _student{
int xh;
double grade;
struct _student * next;
}student;
int main()
{
student * head= NULL ,*p;
head=(student*)malloc(sizeof(student));
head->next=NULL;
p=NULL;
int n;
printf("请输入班级人数:");
scanf("%d",&n);
int i;
for(i=1;i<=n;i++)
{
p=(student*)malloc(sizeof(student));//首先记得分空间!!!
printf("请依次输入第%d个学生学号 成绩:",i);
scanf("%d %lf",&p->xh,&p->grade);
p->next=head->next;//让p的下一个结点等于head的下一个结点
head->next=p;//让head的下一个结点等于p
}
student * q;//输出
for(q=head->next;q;q=q->next){
printf("%d %.1lf\n",q->xh,q->grade);
}
return 0;
}
输入:
输出:
知识总结:
-
链表的头,结点,尾找好,首先malloc。
-
头插:
注意最后一个结点指向NULL:即初始化head->next=NULL;
node->next=head->next;
head->next=node; -
尾插:
end->next=node;
end=node;
注意最后一定要加上:end->next=NULL; -
sizeof()这个函数返回的是一个对象或者类型所占的内存字节数,也就是说sizeof 数组是返回定义时的数组长度 * 数组类型长度,例如:
int a[10];
sizeof(a)=10 * 4=40
而sizeof 结构体就是整个结构体的内存字节数,注意不同类型字节对齐情况。 -
stdlib .h 头文件定义了四个变量类型、一些宏和各种通用工具函数。
-.NULL 这个宏是一个空指针常量的值。
- void * malloc(size_t size) 分配所需的内存空间,并返回一个指向它的指针。
- void exit(int status) 使程序正常终止。
- void qsort(void *base, size_t nitems, size_t size, int (*compar)(const void , const void)) 数组排序。
- int abs(int x) 绝对值
- int rand(void) 返回一个范围在 0 到 RAND_MAX 之间的伪随机数。
4.在第3题的基础上完成功能:输入一个数N,输出第N个学生的信息。
#include<stdio.h>
#include<stdlib.h>
void * creat(int n,int N);
typedef struct _student{
int xh;
double grade;
struct _student * next;
}stu;
int main()
{
int n;
printf("请输入班级人数:");
scanf("%d",&n);
int N;
printf("请输入一个数N:");
scanf("%d",&N);
creat(n,N);
return 0;
}
void * creat(int n,int N)
{
stu * head=NULL,* node,* end;
head=(stu*)malloc(sizeof(stu));
end=head;
int i,a;
double b;
for(i=1;i<=n;i++)
{
node=(stu*)malloc(sizeof(stu));
printf("依次输入第%d个学生学号 成绩:",i);
scanf("%d %lf",&node->xh,&node->grade);
if(i==N){//在这里记录下第N个学生
a=node->xh;
b=node->grade;
}
end->next=node;
end=node;
}
end->next=NULL;
printf("%d %.1lf",a,b);
}
输入:
输出:
5. 在第4题的基础上完成功能:对学生信息按照成绩值进行排序,排序方法不限(参考排序方式:冒泡(交换),选择,插入,希尔等)。
冒泡:
#include<stdio.h>
#include<stdlib.h>
typedef struct _student{
int xh;
double grade;
struct _student * next;
}stu;
stu * creat(int n);
stu * bubblesort (stu * head);
int main()
{
int n;
printf("请输入班级人数:");
scanf("%d",&n);
stu * head=creat(n);
stu * p;
bubblesort(head);
//输出检测
for(p=head;p&&p->next;p=p->next){
printf("%d %.1lf\n",p->xh,p->grade);
}
return 0;
}
stu * creat(int n){
stu * head=NULL,* node,*end;
head=(stu*)malloc(sizeof(stu));
end=head;
int i;
for(i=1;i<=n;i++)
{
node=(stu*)malloc(sizeof(stu));
printf("依次输入第%d个学生学号 成绩:",i);
scanf("%d %lf",&node->xh,&node->grade);
end->next=node;
end=node;
}
end->next=NULL;
return head;
}
stu * bubblesort (stu * head){
if(head == NULL || head->next == NULL)return head;//首先排除链表为空的情况
stu *p = NULL;//为了排除只有两个结点,所以没有发生交换结点的情况
bool isChange = true;
while(p != head->next && isChange)//当p是head的下一节点或者没有发生结点交换时,结束循环
{
stu * q = head;//先让q指针从head开始移动
isChange = false;//标志当前这一轮中又没有发生结点交换,如果没有则表示链表已经有序
for(; q->next && q->next != p; q = q->next)//当q的下一节点为空或者等于p,结束循环
{
if(q->grade < q->next->grade)//交换结点数据
{
int a=q->xh;
double b=q->grade;
q->xh=q->next->xh;
q->grade =q->next->grade;
q->next->xh=a;
q->next->grade=b;
isChange = true;
}
}
p = q;//一轮结束后,让p的位置=q最后移动到的结点
}
return head;
}
输入:
输出:
知识总结:
- 在使用函数的时候一定要记得将head 传出来,所以函数类型就是指向结构体的指针(stu * ).
- bool类型,和int、float一样是数据类型的一种,bool函数只返回true和false
8. 从键盘输入一个字符串,将其中的小写字母全部转换成大写字母,然后输出到一个磁盘文件“test ”中保存,输入的字符串以!表示结束。
#include<stdio.h>
#include<stdlib.h>
#include<string>
using namespace std;
int main()
{
FILE * fp;
char filename[20],str;
printf("请输入要打开的文件名:");
scanf("%s", filename);
getchar();
fp=fopen(filename,"w");
if(fp){
printf("请输入str=");
while(1){
str=getchar();
if(str=='!'){
break;
}else if(str>='a'&&str<='z'){
str=str-32;
}
fputc(str,fp);
//putchar(str);
}
}else{
printf("无法打开文件");
}
printf("\n");
printf("已完成!");
fclose(fp);
return 0;
}
输入:
输出:
知识总结:
- %s会一直赋值,直到输入中遇到空白字符为止,scanf(“%s”,a),注意a前面一定没有&符号,但scanf(“%c”,&b),输入单个字符的时候要加上&
- 先打开文件fopen(),最后关闭文件fclose(),有开就有关,记得末尾的fclose(fp);
- fgetc 从文件中读取一个字符 ,fputc 写一个字符到文件中去
- fgets 从文件中读取一个字符串, fputs 写一个字符串到文件中去
- fprintf 往文件中写格式化数据, fscanf 格式化读取文件中数据
- fread 以二进制形式读取文件中的数据, fwrite 以二进制形式写数据到文件中去
- getw 以二进制形式读取一个整数,putw 以二进制形式存贮一个整数
- ferror 文件读/写出错
9. 以二进制打开 test.txt 文件,读取出来,加上行号并显示在屏幕上。
#include<stdio.h>
#include<stdlib.h>
#include<bits/stdc++.h>
using namespace std;
int main() {
int line=0;
char ch[10000]={0};
FILE *fp=fopen("test.txt","r");
if (fp) {
while(!feof(fp)) {
fscanf(fp,"%[^\n]%*c",ch);//读入文件直到遇到\n为止,即读入一行存入ch,%*c为忽略一个字符(即换行符)
line++;
printf("<%d>%s\n",line,ch);
memset(ch,0,sizeof(ch));
}
fclose(fp);
} else {
printf("无法打开文件");
}
return 0;
}
输入:
无
文件:
输入:
知识总结::
- feof()函数是检测流上的文件结束符的函数,如果文件结束,则返回非0值,否则返回0
- feof()只用于测试流文件的结束,当到达结尾时,返回非0;当文件内部位置指针指向文件结束时,并未立即置位FILE结构中的文件结束标记,只有再执行一次读文件操作,才会置位结束标志,此后调用feof才会返回为真。
10.文本文件score.txt 中存储了n名学生的信息(班级编号,姓名,成绩),每个学生信息占一行,每行的数据之间使用制表符(tab)分割,如下所示:
145811 fuxin 100
145811 chengxian 90
145812 zhangxue 92
145812 lijun 88
……
文件中存储的学生信息按照班级编号升序排列,每个班级的人数可以不同,要求读取文件中所有学生的成绩,计算每个班级的平均成绩,将班级编号和平均成绩输出。
#include<stdio.h>
#include<stdlib.h>
#include<bits/stdc++.h>
using namespace std;
int main()
{
int curclass=0,lastclass=0,curscore=0;
int num=0;
int s=0;
FILE * fp=fopen("score.txt","r");
if(fp){
while(fscanf(fp,"%d %*s %d",&curclass,&curscore)!=EOF){
if(lastclass==curclass||lastclass==0){
s+=curscore;
num++;
lastclass=curclass;
}
else{
printf("%d\t%.1lf\n",lastclass,s*1.0/num);
num=1;
s=curscore;
lastclass=curclass;
}
}
printf("%d\t%.1lf\n",lastclass,s*1.0/num);
fclose(fp);
}else{
printf("无法打开文件!");
}
return 0;
}
输入:
无
文件:
输出:
知识总结:
- EOF为End Of File的缩写,常被作为文件结束的标志。还有很多文件处理函数处错误后的返回值也是EOF,因此常被用来判断调用一个函数是否成功。
- 通常EOF在while(scanf(“%d %d”,&a,&b)!=EOF)中使用,如果a和b都被成功读入,那么scanf的返回值就是2;如果只有a被成功读入,返回值为1;如果a和b都未被成功读入,返回值为0;如果遇到错误或遇到end of file,返回值为EOF,且返回值为int型。