课堂案例代码 持续补充 文章-1

 B站视频 C++就业班  本文都是C语言的 前面的基础课程  ,从文章-2开始对应数据结构

1.文件读写相关

1.1. 文件版  四则运算

现在文件里用函数写进4个等式 但是不写结果 

在while循环中,如下处理每一行

然后用fgets读出每一行,sscanf提取变量值,进入switch算出结果,然后sprintf打印出带着结果的一个完整等式。

最会strcat拼接成一个大字符串(所有内容) w 模式清空文件并重写进去。

#include <stdio.h>
#include <stdlib.h>
#include<string.h>

//文件版四则运算
//在yunsuan.txt里写了4个算式 
//用fwrite写还是事先自己写 

	char allres[1024]={0};
void writeOne(void) {
	FILE *fp1=fopen("yunsuan.txt","w");
	if(!fp1){
		perror("打开失败");
		return ;
	}
	fputs("12+3=\n",fp1);
	fputs("20-5=\n",fp1);
	fputs("3*4=\n",fp1);
	fputs("24/6=\n",fp1);
	fclose(fp1);
}
void getres(){
		FILE *fp2=fopen("yunsuan.txt","r");
		if(!fp2){
			perror("打开失败");
			return ;
		}
		char buf[1024];//先把整个文件读出来
		//这样才方便删除所有文件原来部分 
		int a;
		int b;
		char c;
		int res;
		char resline[100];
		while(1){
			fgets(buf,1024,fp2);
			if(feof(fp2)){
			 	break;
			}
			printf("%s",buf);
			sscanf(buf,"%d%c%d=\n",&a,&c,&b);
			//printf("%d   %d  %c\n",a,b,c);
				switch (c) {
					case '+':
						res=a+b;
						break;
					case '-':
						res=a-b;
						break;
					case '*':
						res=a*b;
						break;
					case '/':
						res=a/b;
						break;
					default:
						printf("没有找到运算符");
						break;
				}
		    sprintf(resline,"%d%c%d=%d\n",a,c,b,res);
		    printf("%s\n",resline);//test0
		    strcat(allres,resline);
		}
	   	printf("-----------------\n");
	printf("%s",allres);
	fclose(fp2);
}
void rewrite(){
	//w是直接全部清空的 模式 
	FILE *fp3=fopen("yunsuan.txt","w");
		if(!fp3){
			perror("打开失败");
			return ;
		}
	fputs(allres,fp3);
		fclose(fp3);
}
int main(void) {

writeOne();
getres();
rewrite();
   return EXIT_SUCCESS;	
   	system("pause");
}

1.2.fread  fwrite   大文件拷贝

自己写了一个 但是只能复制图的 黑背景??。用二进制读写就没事了

自己写的函数缺陷:每次调用先得改新文件的名字。导致必须复制一次函数整体。

例1:复制yunsuan.txt 文本文件
void mycopyb(char* pathname){
		FILE *fp1=fopen(pathname,"rb+");
		if(!fp1){
				perror("打开失败");
				return ;
		}
		char cont[1024]={0};
		FILE *fp2=fopen("mycopy.txt","wb+");
			if(!fp2){
				perror("打开失败");
				return ;
			}
		while(!feof(fp1)){
			fread(cont,1,1024,fp1);
			fwrite(cont,1,1024,fp2);
		}
		fclose(fp1);
	
		fclose(fp2)	;	
	}
	int main(void) {
	
	//测试一个txt文件 注意括号里参数写原文件
	//函数缺陷是新文件名必须现改 重复写函数 
	 mycopyb("yunsuan.txt");
	
	   return EXIT_SUCCESS;	
	   	system("pause");
	}
例2:复制一个jpg 文件ab.jpg   看老师的代码 修改,加上一个fread的返回值,

当返回值等于0时说明读取失败

void mycopyb(char* pathname){
		FILE *fp1=fopen(pathname,"rb+");
		if(!fp1){
				perror("打开失败");
				return ;
		}
		char cont[1024]={0};
		int ret=0;
		FILE *fp2=fopen("mycopy2.jpg","wb+");
			if(!fp2){
				perror("打开失败");
				return ;
			}
		while(!feof(fp1)){
		    ret=fread(cont,1,1024,fp1);
			if(ret==0){
				break;
			}
			fwrite(cont,1,1024,fp2);
		}
		fclose(fp1);
	
		fclose(fp2)	;	
	}
int main(void) {
	mycopyb("ab.jpg");
	return EXIT_SUCCESS;	
	system("pause");
	}

1.3 游戏配置文件解析

假设有个游戏文件,记录了游戏角色的各种信息,txt中信息如下:

#英雄ID
heroID:zhaoyun
#英雄能力
heroskill:fight
#英雄道具
herotool:bigknife
#英雄血量
heroHP:10000
#英雄防御能力
herotank:20000

通过读文件操作过滤无效信息,将记录保存到结构体数组中。 

#include <stdlib.h>
#include <stdio.h>
#include <string.h>


struct info{
	char key[256];
	char val[256];
};
//多少行有效信息  
int lines(){
    int ll=0;
    FILE *fp=fopen("gameinfo.txt","r");
    if(fp==NULL){
		perror("文件没有打开");
	}

	char buf[256]={0};
	while(fgets(buf,256,fp)!=NULL){
        if(strchr(buf,':')!=NULL){
			printf("%s\n",buf);
			ll++;
		//	sscanf(buf,"%s:%s",key,val);
			//	printf("key是%s,val是    %s\n",key,val);	
			//这样吧整个一行都算成key  也又算成val 了!!
			//必须用字符串截取函数
			 
		//memset(key,0,128);
	//	memset(val,0,128);
		}
		memset(buf,0,256);	
	}
	fclose(fp);
    return ll;
} 

//从文件中,提取有效信息放到  数组中
void putarr(struct info **infoARR,int len){
    struct info *arr=(struct info *)malloc(sizeof(struct info)*len);
    int index=0;
    FILE *fp2=fopen("gameinfo.txt","r");
   	    if(fp2==NULL){
   	   	perror("文件没有打开");
   	}
   	char buf2[256]={0};
   	while(fgets(buf2,256,fp2)!=NULL){
	    if(strchr(buf2,':')!=NULL){
	    	memset(arr[index].key,0,256);
			memset(arr[index].val,0,256);
	    	char *pos=strchr(buf2,':');
	   		strncpy(arr[index].key,buf2,strlen(buf2)-strlen(pos));
		    strncpy(arr[index].val,pos+1,strlen(pos-1));
	   		index++;
            if(index==len){
			   break;
			}
	   	
	   	}
		memset(buf2,0,128);		
	}
   fclose(fp2);
    *infoARR=arr; 	
}
//先遍历一下数组 看看弄好了么
void printALL(struct info *arr,int len){
 	for(int i=0;i<len;i++){
 		printf("%s    is    %s\n",arr[i].key,arr[i].val);
	 }
 } 

//cesh测试,根据英雄的key,打印出属性值,要求对应正确。
void getval(const char *kword,struct info *arr,int len){
	int flag=0;
	for(int i=0;i<len;i++){
	 	if(strcmp (arr[i].key,kword)==0){
			printf("the attribute is %s ",arr[i].val);
			flag=1;
		 }
		  
	}
	if(flag==0){
		printf	("no such attribution\n");
	}
} 
 
int main()
{
	int nums=lines();
	printf("有效信息一共 %d 行 \n",nums);
 	struct info *ptrIn=NULL;
 	putarr(&ptrIn,nums);
 	printALL(ptrIn,nums);
    getval("heroHP",ptrIn,nums);
     //getval("heroMP",ptrIn,nums);  //no such attribution
system("pause");
   return 0;
  }

1.4 文件的加密和解密

把所有字符进行位运算,先左移4位,再右移1位,然后变更符号位。

解密时,先左移1位 再右移5位 (??高位4位会丢失,这里没看明白)

void code(const char* fileA, const char* fileB){
	FILE *fp=fopen(fileA,"r");
	FILE *fp2=fopen(fileB,"w");
	if(fp==NULL){
		perror(" open is fail\n");
	}
	if(fp2==NULL){
		perror(" open is fail\n");
	}
	char ch;
	short temp;
	while((ch=fgetc(fp))!=EOF){
		temp=(short)ch;
		temp=temp<<4;
		temp=temp|0x8000;//1000 0000 0000 0000  两字节哦 
		//printf("%d\n",temp);
	   fprintf(fp2,"%hd",temp);
	}
	fclose(fp);
	fclose(fp2);
}

void decode(const char* fileB, const char* fileC){
	FILE *fp3=fopen(fileB,"r");
	FILE *fp4=fopen(fileC,"w");
	if(fp3==NULL){
		perror(" open3 is fail\n");
	}
	if(fp4==NULL){
		perror(" open4 is fail\n");
	}
char ch;
short temp;
	while(!feof(fp3)){
		fscanf(fp3,"%hd",&temp);
		temp=temp<<1;
	     temp=temp>>5;
	     //疑问,最开始最高位那4个数字无法恢复了。。 
		printf("%d\n",temp);
	    ch=(char)temp;
	    fputc(ch,fp4);
	}
	fclose(fp3);
	fclose(fp4);
}
int main()
{
	code("incode.txt","decode.txt");
	decode("decode.txt","res.txt");
	//打开res 和incode看是不是一模一样就行 
	system("pause");
   return 0;
  }

2.指针基础属性

2.1利用指针步长,获取结构体属性的值。

struct Person{
	int a;
	char b;
	char buf[64];
	int d;
};


int main (){


struct Person p1={100,'w',"water cup",12};
printf("%d\n",sizeof(p1));    //76
 // char *pp=&p1;   BAO CUO ERROR
  printf("属性d的值是%d\n",*((char*)&p1+72));

 2.2  offsetof( struct 结构体名,属性名) 函数

    #include<stddef.h>

 struct Person p1={100,'w',"water cup",12};
 int aaa=offsetof(struct Person,d);
printf("%d\n",aaa);  //72

3.数据结构方面基础代码

3.1 带头节点的链表

创建在堆上的 叫做动态链表。头结点没有数据,只有一个指针域。

创建initList  ,遍历foreach, 释放freeList 三个函数。

外加一个插入函数,第一个参数是头结点,第二个参数int old是在数据等于old的节点后面插入,第三个参数是插入的新值。

#include <stdio.h>
#include <stdlib.h>  
#include<string.h> 


struct Node{
	int num;
	struct Node* next;
};
//初始化链表  
struct Node* initList(){
	struct Node* phead;
	if(phead==NULL){
		perror("FAIL IN MALLOC");
	}
	phead=(struct Node *)malloc(sizeof(struct Node));
	phead->next=NULL;
    struct Node* ptail=phead;
		int n=0;
		while(1){
			int m=0;
			printf("Please type in the %d th number\n",n+1);
			
			scanf("%d",&m);
			if(m==-1){
				printf("List ends\n");
				break;
			}
			else{
				struct Node* ptr=(struct Node *)malloc(sizeof(struct Node));
				ptr->num=m;
				ptr->next=NULL;
				n++;
				ptail->next=ptr;
				ptail=ptr;
			}
		
		}
	return phead;

};

//链表的遍历
void foreach(struct Node* header){
	if(header==NULL){
			perror("list is NULL");
		}
	while(header->next!=NULL){
		header=header->next;
		printf("the num is %d\n",header->num);
		
	}
}

//再链表某个值的后面插入一个新值
void listinser(struct Node* header,int old,int newval){
	if(header==NULL){
		perror("list is NULL");
	}
	struct Node* ptr=header->next;
	while(ptr!=NULL){
		if(ptr->num==old){
			break;
		}
		ptr=ptr->next;
	}
	if(ptr==NULL){
		printf("no such data in the list\n");
		return;
	}
	struct Node* newnode=(	struct Node*)malloc(sizeof(struct Node));
	newnode->num=newval;
	newnode->next=ptr->next;
	ptr->next=newnode;
}
//摧毁整个链表
void listfree(struct Node* list){
	if(list==NULL){
		perror("list is NULL");
	}
	struct Node* pp=list;
	while((list->next)!=NULL){
		list=list->next;
		free(pp);
		pp=NULL;
		pp=list;
	}
	free(list);
	list=NULL;
}


int main(void) {
	struct Node* mylist=initList();
	foreach(mylist);
	listinser(mylist,30,2000);
	printf("插入操作完成,现在链表重新遍历\n");
	
	foreach(mylist);
   listfree(mylist);
   free(mylist);
   mylist=NULL;
   if(mylist==NULL){
   	   printf("right\n");
   }
	system("pause");
	return EXIT_SUCCESS;
	
} 
3.1.1按照位置来插入 新节点。

第二个参数pos表示在第几节点后面插入新节点,头结点当做第0个。

void listinsBpos(struct Node* header,int pos,int newval){
	if(header==NULL){
			perror("list is NULL");
	}
	int inpos=0;
	struct Node* ptr=header;
	while(ptr!=NULL){
		if(inpos==pos){
	  		break;
	    }	
	  ptr=ptr->next;
	  inpos++;
	}
	if(ptr==NULL){
			printf("no such data in the list\n");
			return;
	}
	struct Node* newnode=(	struct Node*)malloc(sizeof(struct Node));
	newnode->num=newval;
	newnode->next=ptr->next;
	ptr->next=newnode;
}
3.1.2 链表倒置

头结点为pheader ,第一个有数据域的节点为p1 , 后面依次为p2, p3 每次让p2->next = p1 然后再移动p1  p2的位置就可以了。

void reverLink( struct Node* head ){
	struct Node* p1=head;
	struct Node* p2=head->next;
	struct Node* p3=p2->next;
	if(p3==NULL){
		printf("only one NODE having data\n");
		return;
	}
	p2->next=NULL; //第一个有数据域的节点,成为尾巴,next 为NULL 
	p1=p2;
	p2=p3;	
	while(p2!=NULL){
		struct Node* pnext=p2->next;
		p2->next=p1;
		p1=p2;
		p2=pnext;	
	} 
	head->next=p1;//把头节点挪过来,让它指向原来的尾巴 
}

4.模拟或者改写字符串相关API

4.1   字符串复制函数strcpy

3种方式 zhuyi注意第三种,赋值为0 退出while循环

void mycopy(char *str1,char *str2){
	int num=strlen(str1);
	for(int i=0;i<=num;i++){
	    str2[i]=str1[i];
	}
}
	
void mycopy2(char *str1,char *str2){
	int num=strlen(str1);
	while(*str1!='\0'){
			*str2=*str1;
			str1++;
			str2++;
	}
}
	
void mycopy3(char *str1,char *str2){
	while(*str2++=*str1++){
	}	
}
	
void mytest(){
	char ss1[64]="gets water";
	char ss2[64]={0};
	//	mycopy(ss1,ss2);
	//mycopy2(ss1,ss2);
	//mycopy3(ss1,ss2);
    printf("%s\n",ss2);
}

4.2  字符串翻转函数

void myverse(char *str){
		int num=strlen(str);
		int a=0;
		int b=num-1;
		while(a<b){
			char temp='0';
			temp=str[a];
			str[a]=str[b];
			str[b]=temp;
			a++;
			b--;
		}
}

利用指针

void rev2(char *buf){
		int num=strlen(buf);
		char temp='0';
	char *start=buf;
	char *end=buf+num-1;
	while(start<end){
		temp=*start;
		*start=*end;
		*end=temp;
		start++;
		end--;
	}
}

4.3 判断一个字符串是否回文

视频中老师的写法 

int str_huiwen(char *str){
	char *start=str;
	char *end=start+strlen(str)-1;
	while(start<end){
		if(*start!=*end){
			return 0;
		}
		start++;
		end--;		
	}
	return 1;
}

自己写法

bool huiwen(char *str){
	char *start=str;
	char *end=start+strlen(str)-1;
	while(*start==*end){
		start++;
		end--;	
		if(start>end){
			return true;
			break;
		}
	}
	return false;
}

4.4 字符串查找strstr( )模拟

 注意,C语言中strstr 函数是返回地址(就是子串在母串中的首地址 ), 还是一个可以打印的字符串,但是我这个函数返回的是子串的第一个字母是母串的第几个字符。

int mystrsub(const char *str,const char*sub){
	int num=0;
	while(*str!='\0'){
		if(*str==*sub){
		    const char *temp1=str;
		    const char *temp2=sub;
		    while(*sub!='\0'){
			    if(*temp1!=*temp2){
				    break;
			    }
			    temp1++;
			    temp2++;
		    }
			if(*temp2=='\0'){
			    printf("子串匹配成功位置是%d\n",num);
				return num;	
			}	
	    }
	    str++;
	    num++;
	}
    return -1;
} 
	

	void test2(){
		const char *word="adegdnfhi";
		const char* subword="dnf";
		int ret=mystrsub(word,subword);
		printf("%d\n",ret);
	}

 4.5  在母串中,子串出现的次数

这个是利用了库自带的strstr( )函数

字符串查找 找到的次数  利用已有的strstr   <string.h> 
int ser_time(char *sear,char*tar){
    int k=strlen(tar);
    int count=0;
    char *r=strstr(sear,tar);
	while(r!=nullptr){
		printf("%s\n",r);
		r+=k;
		count++;
	    r=strstr(r,tar);//再新的  掐去了头的 字符串里寻找 
	}
	return count;
}

 4.6字符串复制

4.7 strlen字符串长度统计功能

//zhi利用传统功能实现 strlen功能 
 int mystrlen(char str[]){
 	int i=0;
 	while(str[i]!='\0'){
 		i++;
 	}
 	return i;
 }
  //zhi利用指针实现 strlen功能 
  int mystrlen2(char str[]){
  
  	char *cp=str;
  	while((*cp)!='\0'){
  		//'\0'  不是空格,是NULL字符啦,是一个字符串的结束 
  	cp++;
  	}
  	return cp-str;
  }

5.一些基础小例子

5.1 模拟电子表打印

#include <windows.h>       //Sleep()函数

	for(int i=0;i<24;i++){
		for(int j=0;j<60;j++){
	   		for(int k=0;k<60;k++){
			   	printf("%02d : %02d : %02d\n",i,j,k);
			   	Sleep(1000);
			   	system("cls");//清除屏幕 
			}
	   }
	}

??C语言日期函数?待补充 

5.2 99乘法表 

    for(int i=1;i<9;i++){
		for(int j=1;j<=i;j++){
			printf("%d * %d = %d  ",j,i,j*i);
		}
		printf("\n");
	}

5.3 水仙花数字

5.4 猜数字 

#include <time.h>     //  srand(time(NULL))

总是自动有个空格输入导致自动跳转无限循环      解决办法

    srand(time(NULL));
	int r_num=rand()%101+1;   //1-100
	int a;
	while(1){
		printf("请输入数字\n");
		scanf("%d",&a);
		    while(getchar()!='\n'){
			continue;
		    }
		if(a==r_num){
			printf("猜对了");
		}
		else{
			printf("猜错了,是否继续, Y N\n");
			char n;
		scanf("%c",&n);
			if(n=='N'){
				 printf("输入的字符是%c,表示您拒绝继续\n",n);
			  break;
			}
		}
	}

5.5统计字符串中各个字母出现次数 

char example[25] ="there is a big lake";
int countarr[26]={0};
//一个整数 数组,共26个数字,代表26个字母。初始化每个数都是零 
	for(size_t i=0;i<25;i++){
		if(!isblank(example[i])){   //头文件cctype 
			int count=static_cast<int>(example[i]-'a');
			countarr[count]++;  
		}
    }

//printf("现在统计结果\n");
for(size_t j=0;j<26;j++){
	if(countarr[j]!=0){
		printf("%c字母在句子中出现次数是%d\n",j+'a',countarr[j]);
	}
 //j +'a'隐形数据类型转换,不放心的可以用(char)强制转 
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值