复习文件: 编写程序实现文件拷贝功能
./a.out 路径一 路径二
./a.out a.txt b.txt a已存在,b是复制出来的
1#include<stdio.h>
2int main(int argc,char *argv[]/* **argv */){
3 int size=0;
4 FILE*p_src=NULL,*p_dest=NULL;
5 char buf[100]={0};
6 if(argc<3){
7 printf("命令错误\n");
8 return 0;
9 }
10 p_src=fopen(*(argv+1),"rb");
11 if(!p_src){
12 printf("原始文件打开失败\n");
13 return 0;
14 }
15 p_dest=fopen(*(argv+2),"wb");
16 if(!p_dest){
17 printf("目标文件打开失败\n");
18 fclose(p_src);
19 p_src=NULL;
20 return 0;
21 }
22 while(1){
23 size=fread(buf,sizeof(char),100,p_src);
24 //从文件中拿出100个字节放到存储区
25 if(!size){
26 break;
27 } // 若最后一字不足100字节,两个文件大小就不一样,所以用size来算字节
28 fwrite(buf,sizeof(char),size,p_dest);
29 }
30 fclose(p_dest);
31 p_dest=NULL;
32 fclose(p_src);
33 p_src=NULL;
34 return 0;
35 }
数据结构:
数据结构研究如何使用存储区解决问题
算法研究解决一些常见问题的方法
数字之间的关系可以从两个完全不同的角度进行描述
逻辑关系(逻辑结构):描述数字之间的关系,和计算机无关。
物理关系(物理结构):描述存放数字的存储区之间的关系。
逻辑结构分为如下几种:
1、 集合结构:所有数字元素是一个整体,它们之间没有其他关系
2、 线性结构:可以用一条有顺序的线把所有数字连接起来
3、 树状结构:所有数据都是从一个数据开始向一个方向扩展出来,任何数据都可以扩展出多个其他数据
4、 图形结构:图形结构的数据元素是多对多的,任何两个数字之间可以有直接联系,所有数字之间的联系没有统一方向
物理结构有以下两种:
1、 顺序结构:所有存储区在内存里连续排列(数组和动态分配内存都是顺序结构的例子) 顺序结构中每个存储区都有一个编号(内存地址),可以根据编号直接找到对应的存储区,(数组)根据编号找到存储区的方法叫做随机访问。顺序结构支持随机访问能力。缺点:顺序结构中存储区个数(内存大小)很难调整,可能造成内存的浪费。顺序结构不适合进行插入或删除文件。
例: 在顺序结构中插入数字:
1#include<stdio.h>
2void insert(int *p_num,int size,int num){
3 int tmp=num,num1=0,tmp1=0;
4 for(num1=0;num1<=size-1;num1++){
5 if(tmp<*(p_num+num1)){
6 tmp1=tmp;
7 tmp=*(p_num+num1);
8 *(p_num+num1)=tmp1;
9 }
10 else if(/*tmp>*(p_num+num1)&&*/num1&&*(p_num+num1-1)>*(p_num+num1)){
// 考虑数组的第一个元素不能与之前存储区(不在数组里)的数值比较,并且考虑到临时存储区tmp与后面0的比较
11 tmp1=tmp;
12 tmp=*(p_num+num1);
13 *(p_num+num1)=tmp1;
14 break;
15 }
16 }
17 }
18int main(){
19 int arr[20]={2,6,12,14,17,21,23,31,35,37};
20 int num=0;
21 insert(arr,20,27);
22 for(num=0;num<=19;num++){
23 printf("%d ",arr[num]);
24 }
25 printf("\n");
26 return 0;
27 }
从顺序结构中删除数字:
1#include<stdio.h>
2void remove_num(int *p_num,int size,int num){
3 int num1=0;
4 for(num1=0;num1<=size-1;num1++){
5 if(num<*(p_num+num1)){
6 *(p_num+num1-1)=*(p_num+num1);
7 }
8 elseif(num1&&*(p_num+num1)<*(p_num+num1-1)){
9 *(p_num+num1-1)=*(p_num+num1);
10 break;
11 }
12 }
13 }
14int main(){
15 int arr[20]={2,6,12,14,17,21,23,31,35,37};
16 int num=0;
17 remove_num(arr,20,37);
18 for(num=0;num<=19;num++){
19 printf("%d ",arr[num]);
20 }
21 printf("\n");
22 return 0;
23 }
2、链式物理结构:由多个无关的存储区构成,任何两个存储区之间可以用指针连接
链式物理结构中每个存储区叫做一个节点
单向线性链式物理结构中任何两个节点之间都有前后关系(每个节点里只包含一个指针)
单向线性链式物理结构中最后一个节点里的指针必须是空指针
例:
1#include<stdio.h>
2typedef struct node{
3 int num;
4 struct node *p_next;
5 }node;
6int main(){
7 nodenode1={1},node2={5},node3={12};
8 node1.p_next=&node2;
9 node2.p_next=&node3;
10 return 0;
11 }
链式物理结构不直接支持随机访问能力
在所有节点前增加一个无效头结点,在所有结点后增加一个无效尾结点,这样可以简化程序的编写
1 #include<stdio.h>
2typedef struct node{
3 int num;
4 struct node *p_next;//指向结构体类型的指针
5}node;
6int main(){
7 nodenode1={1},node2={5},node3={12},head={0},tail={0};
8 node1.p_next=&node2;
9 //结点1的指针指向结点2的地址(结构体和int,char是并行关系,都用&表示其地址)
10 node2.p_next=&node3;
11 head.p_next=&node1;
12 node3.p_next=&tail;
13 return 0;
14 }
遍历打印
1#include<stdio.h>
2typedef struct node{
3 int num;
4 struct node *p_next;//指向结构体类型的指针
5}node;
6int main(){
7 nodenode1={1},node2={5},node3={12},head={0},tail={0};
8 node *p_node=NULL;
9 node1.p_next=&node2;
10 //结点1的指针指向结点2的地址(结构体和int,char 是并行关系,都用&表示其地
址)
11 node2.p_next=&node3;
12 head.p_next=&node1;
13 node3.p_next=&tail;
14 for(p_node=&head;p_node!=&tail;p_node=p_node->p_next){
15 node *p_first=p_node;
16 node *p_mid=p_first->p_next;
17 node *p_last=p_mid->p_next;
18 if(p_mid!=&tail){ //p_first->next!=NULL;只要有数字
19 printf("%d",p_mid->num);
20 }
21 }
22 return 0;
打印编号为2的数字:(12)
1#include<stdio.h>
2typedef struct node{
3 int num;
4 struct node *p_next;//指向结构体类型的指针
5}node;
6int main(){
7 int cnt=0;
8 nodenode1={1},node2={5},node3={12},head={0},tail={0};
9 node *p_node=NULL;
10 node1.p_next=&node2;
11 //结点1的指针指向结点2的地址(结构体和int,char 是并行关系,都用&表示其地
址)
12 node2.p_next=&node3;
13 head.p_next=&node1;
14 node3.p_next=&tail;
15 for(p_node=&head;p_node!=&tail;p_node=p_node->p_next){
16 node *p_first=p_node;
17 node *p_mid=p_first->p_next;
18 node *p_last=p_mid->p_next;
19 if(p_mid!=&tail&&cnt==2){
20 printf("数字是%d\n",p_mid->num);
21 }
22 cnt++;
23 }
24 return 0;
25 }
插入:将7插进去,按大小排列
1#include<stdio.h>
2typedef struct node{
3 int num;
4 struct node *p_next;//指向结构体类型的指针
5}node;
6int main(){
7 int cnt=0;
8 node node1={1},node2={5},node3={12},head={0},tail={0},node4={7};
9 node *p_node=NULL;
10 node1.p_next=&node2;
11 //结点1的指针指向结点2的地址(结构体和int,char 是并行关系,都用&表示其地
址)
12 node2.p_next=&node3;
13 head.p_next=&node1;
14 node3.p_next=&tail;
15 for(p_node=&head;p_node!=&tail;p_node=p_node->p_next){
16 node *p_first=p_node;
17 node *p_mid=p_first->p_next;
18 node *p_last=p_mid->p_next;
19 if(p_mid==&tail||p_mid->num>node4.num){
20 p_first->p_next=&node4;
21 node4->p_next=p_mid;
22 break;
23 }
24 }
25 for(p_node=&head;p_node!=&tail;p_node=p_node->p_next){
26 node *p_first=p_node;
27 node *p_mid=p_first->p_next;
28 node *p_last=p_mid->p_next;
29 if(p_mid!=&tail){
30 printf("%d ",p_mid->num);
31 }
32 }
33 printf("\n");
34 return 0;
35 }
删除:将5删去
1#include<stdio.h>
2typedef struct node{
3 int num;
4 struct node *p_next;//指向结构体类型的指针
5}node;
6int main(){
7 // int cnt=0;
8 nodenode1={1},node2={5},node3={12},head={0},tail={0};
9 node *p_node=NULL;
10 node1.p_next=&node2;
11 //结点1的指针指向结点2的地址(结构体和int,char 是并行关系,都用&表示其地
址)
12 node2.p_next=&node3;
13 head.p_next=&node1;
14 node3.p_next=&tail;
15 for(p_node=&head;p_node!=&tail;p_node=p_node->p_next){
16 node *p_first=p_node;
17 node *p_mid=p_first->p_next;
18 node *p_last=p_mid->p_next;
19 if(p_mid!=&tail&&p_mid->num==5){
20 p_first->p_next=p_last;
21 break;
22 }
23 }
24 //遍历打印
25 for(p_node=&head;p_node!=&tail;p_node=p_node->p_next){
26 node *p_first=p_node;
27 node *p_mid=p_first->p_next;
28 node *p_last=p_mid->p_next;
29 if(p_mid!=&tail){
30 printf("%d ",p_mid->num);
31 }
32 }
33 printf("\n");
34 return 0;
35 }
图示:
First Mid Last 三个指针
Mid指针一般指向有效结点,所以,对mid进行操作
如果插入一个数,插到first 和mid之间
如果删除某一个数,让mid指向删除数的结点,直接让first=last