C实现两个文件的内容输出到同一个屏幕
最后更新于:2022-04-01 14:29:19
编制一个程序,实现将两个文件的内容同时显示在屏幕上,并且最左边的第1-30列 显示文件1的内容,右边第41-70列显示文件2的内容;第75-76列显示两文件该行字符总和,其余列显示空白符。另外,每输出20行内容后,另输出2行空行。
下面看一下我的函数实现:
~~~
#include <stdio.h>
#include <stdlib.h>
#define size 31
char file1[size];
char file2[size];
int i;
int readline(FILE *fp,char *file);
/**
* 编制一个程序,实现将两个文件的内容同时显示在屏幕上,并且最左边的第1-30列
* 显示文件1的内容,右边第41-70列显示文件2的内容;第75-76列显示两文件该行字符
* 总和,其余列显示空白符。另外,每输出20行内容后,另输出2行空行。
*/
int main()
{
FILE *fp1;
FILE *fp2;
char fname1[20]; //文件1的名称
char fname2[20]; //文件2的名称
//统计文件行数
int linecount = 0;
//统计每行字符个数
int countSize = 0;
//判断是否循环
int isRun = 1;
//分别用于保存第一个文件和第二个文件读取的字符数
int count1,count2;
printf("Please enter the name of file1: ");
scanf("%s",fname1);
printf("Please enter the name of file2: ");
scanf("%s",fname2);
fp1 = fopen(fname1,"r");
fp2 = fopen(fname2,"r");
//循环输出文件内容
while(isRun){
count1 = readline(fp1,file1);
count2 = readline(fp2,file2);
if(count1 == 0 && count2 == 0)
break;
if(count1 == 0){
printFirstSpace(0);
}else{
printf("%s",file1);
printFirstSpace(count1);
}
if(count2 == 0){
printSecondSpace(0);
}else{
printf("%s",file2);
printSecondSpace(count2);
}
countSize = count1 + count2;
printf("%d\n",count1+count2);
linecount++;
//每输出20行,打印2行空行
if(linecount == 20){
printf("\n");
printf("\n");
linecount = 0;
}
}
fclose(fp1);
fclose(fp2);
return 0;
}
/**
* 用于读取一行字符串,并返回读取的字符个数
* @param
* fp : 文件指针
* file : 保存读取的字符串
*/
int readline(FILE *fp,char *file){
i = 0;
int c;
while((c = fgetc(fp)) != '\n'){
//如果读取到文件末尾的时候,就返回0
if(feof(fp))
break;
file[i] = c;
i++;
if(i == 30)
break;
}
file[i] = '\0';
return i;
}
/**
* 该方法用于输出第一个空白部分
* @param
* co1 : 第一个文件读取的字符个数
*/
void printFirstSpace(int co1)
{
int spaces = 30 - co1 + 10;
printSpaces(spaces);
}
/**
* 该方法用于输出第二个空白部分
* @param
* co2 : 第二个文件读取的字符个数
*/
void printSecondSpace(int co2)
{
int spaces = 30 - co2 + 5;
printSpaces(spaces);
}
/**
* 该方法用于输出空白
* @param
* spaced : 空白的个数
*/
void printSpaces(int spaces)
{
for(i = 0;i < spaces;i++)
printf(" ");
}
~~~
下面是程序的运行结果:
![这里写图片描述](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2016-05-24_5743c0ad3ea13.jpg "")
这个程序还是很好玩的,这里让我想到了实现一个比较简单的文本比较程序。下一篇博客我们来实现一个文本比较程序。
统计文件中字符个数
最后更新于:2022-04-01 14:29:17
所谓“文件”是指一组相关数据的有序集合。这个数据集有一个名称
叫做文件名。文件通常是驻留在外部介质上的,在使用的时候才调
入内存中。
就文件的分类,有很多种分类方式,在这里我们看一下文件编码方式。
根据文件的编码方式,文件可以分为ASCII码文件和二进制文件。
ASCII文件也称为文本文件,这种文件在磁盘中存放时每个字符对应一个
字节,用于存放对应的ASCII码。例如,数字5678的存储形式为:
ASCII码: 00110101 00110110 00110111 00111000
十进制码: 5 6 7 8
共占用4个字节。ASCII码文件可在屏幕上按照字符显示。
二进制文件是按照二进制的编码方式来存放文件的。例如,数字5678的
存储形式为00010110 00101110,只占两个字节,二进制文件虽然可以在屏幕上显示,但是其内容无法读懂。C语言处理这些文件的时候,并不区分类型,都看成是字符流,按字节进行处理。
文件指针在C语言中用一个指针变量指向一个文件,这个指针称为文件指针。通过文件指针就可对他所指的文件进行各种操作。定义文件指针的一般形式为”FILE “指针变量标识符。其中FILE应为大写,他实际上是由系统定义的一个结构,该结构中含有文件名,文件状态和文件当前位置等信息。在编写源程序的时候,不必关心FILE结构的细节。例如”FILE fp”表示fp是指向FILE结构的指针变量,通过fp即可找到存放某个文件信息的结构变量,然后按照结构变量提供的信息找到该文件,实施对文件的操作。
在C语言中,文件操作都是由库函数来完成的。文件操作主要有打开,读写和关闭等。
**1:文件打开函数fopen**
fopen函数用来打开一个文件,其调用的一般形式为:
文件指针名 = fopen(文件名,使用文件方式)
其中,“文件指针名”必须被说明为FILE类型的指针变量,“文件名”是被打开文件的文件名。
“使用文件方式”是指文件的类型和操作要求。“文件名”是字符串常量或字符串数组。
例如:
FILE fp;
fp = fopen(“file.a”,”r”);
//他的意思是在当前目录下打开文件file.a,只允许进行“读”操作,并且使得fp指向该文件
使用文件的方式一共有12种。
![这里写图片描述](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2016-05-24_5743c0acf2cc8.jpg "")
对于文件使用方式有以下几点说明:
文件使用方式由r,w,a,t,b,+共6个字符组合成,各个字符的含义是:r(read)读,w(write)写,
a(append)追加,t(text)文本文件,可省略不写;b(binary)二进制文件;”+”读和写
用r打开一个文件的时候,该文件必须已经存在,且只能从该文件读出
用w打开的文件只能向文件中写入,若打开的文件不存在,则以指定的文件名建立
该文件,如打开的文件已经存在,则将该文件删去,从新建立一个文件
若要向一个已经存在的文件追加新的信息,只能用a方式打开文件。但此时该文件必须是
存在的,否则将会出错。
在打开一个文件的时候,如果出错,fopen将会返回一个空指针值NULL。在程序中可以
用这一信息来判别是否完成打开文件的工作,并做相应的处理。举个例子:
if((fp=fopen(“file.a”,”rb”)) == NULL)
{
printf(“\nerror no open file.a!”);
getch();
exit(1);
}
**2:关闭文件**
调用的一般形式是:
fclose(文件指针);
正常完成关闭文件操作的时候,fclose函数返回值为0,如返回非零值则表示有错误发生
**3:文件读写函数**
在C语言中提供了很多文件读写的函数。字符读写函数fgetc和fputc;字符串读写函数fgets和
fputs;数据块读写函数fread和fwrite;格式化读写函数fscanf和fprintf;这些函数
都包含在stdio.h头文件中。
**(1):读字符函数fgetc**
fgetc函数的功能是从指定的文件中读取一个字符,函数的调用形式为:
字符变量 = fgetc(文件指针);
注意文件指针和文件内部的位置指针是不同的。文件指针是指向整个文件的,
需要在程序中定义说明,只要不重新赋值,文件指针的值是不变的。文件内部的
位置指针用以指示文件内部的当前读写位置,每读写一次,该指针均向后移动,
他不需要在程序中定义说明,而是由系统自动设置的。
**(2):写字符函数fputc**
fputc函数的功能是把一个字符写入指定的文件中,函数的调用形式为:
fputc(字符,文件指针);
fputc函数有一个返回值,如果写入成功,则返回写入的字符,否则返回EOF
**(3):字符串读写函数fgets和fputs**
读字符串函数fgets函数的功能是从指定的文件中读一个字符串到字符数组中,
函数的调用形式为:
fgets(字符数组名,n,文件指针);
其中n是一个正整数,表示从文件中读出的字符串不超过n-1个字符,在读入的最后
一个字符加上串结束标识’\0’。对fgets函数有两点说明:在读出n-1个字符之前,如果
遇到了换行符或者是EOF,则结束操作。fgets函数也有返回值,其返回值是字符数组的首
地址。
写字符串函数调用形式:
fputs(字符串,文件指针);
**(4):块数据读写函数fread和fwrite**
调用形式:
fread(buffer,size,count,fp);
fwrite(buffer,size,count,fp);
buffer是一个指针,在fread中,他表示存放输入数据的首地址。在fwrite中,
他表示存放输出数据的首地址。size表示数据块的字节数,count表示要读写的
数据块的块数。
**(5)格式化读写函数fcanf和fprintf**
调用形式:
fcanf(文件指针,格式字符串,输入表列);
fprintf(文件指针,格式字符串,输出表列);
下面就是我们这个实例的要求:
~~~
编写统计文件的字符数的程序,主要学习文件的概念
和文件操作等内容。
~~~
下面是我的代码实现:
~~~
#include <stdio.h>
#include <stdlib.h>
/**
* 编写统计文件的字符数的程序,主要学习文件的概念
* 和文件操作等内容。
*/
int main()
{
/**保存字符个数 **/
int count = 0;
/**保存文件名 **/
char fname[80];
/**文件指针 **/
FILE *fp;
printf("Please enter the file name:");
scanf("%s",fname);
if((fp = fopen(fname,"r")) == NULL){
printf("Open file failed!!\n");
exit(1);
}
count = 0;
while(fgetc(fp) != EOF)
count++;
fclose(fp);
printf("There are %d characters in file %s.\n",count,fname);
return 0;
}
~~~
下面是我的测试用例(名称为test.txt):
~~~
cnuidocncn cwncviow
wedcvnwicvmnw
dcvnwidcvn
cvwiovm
wvcewoivm
w
evcovw
vcmweiocvmw
mvciomvw
nvi] v
wevmovjov
wvjkvnivpvm
wvciwmvw
'nvoikvv
nvwvmje
ewevvvv
wvwkvnpowiehf]ewnveiowv
~~~
好了,最后看一下我的运行过程:
![这里写图片描述](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2016-05-24_5743c0ad280c5.jpg "")
除此之外,我们还可以对文件进行随机读写。在C中提供了一些文件定位的函数,我们常用的有两个:rewind和fseek。
这两个函数的调用形式分别为:
rewind(文件指针)。
他的功能是把文件内部的位置指针移到文件首。
fseek(文件指针,位移量,起始点);
将文件内部位置指针移动到我们想要的位置。
模拟社会关系
最后更新于:2022-04-01 14:29:14
本实例有求设计一个模拟社会关系的数据结构,每个人的信息用结构表示,包含名字,性别和指向父亲,母亲,配偶,子女的指针(设只限两个子女)。要求编写以下函数:
1. 增加一个新人的函数
1. 建立人与人之间关系的函数,父子 、母子、配偶等
1. 检查某两人之间是否是堂兄妹
该实例的主要目的是联系C中结构体的使用,下面是函数的实现:
~~~
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define CHILDREN 2
/**
* 设计一个模拟社会关系的数据结构,每个人的信息用结构表示,包含名字,
* 性别和指向父亲,母亲,配偶,子女的指针(设只限两个子女)。要求编写
* 以下函数:(1)增加一个新人的函数 (2)建立人与人之间关系的函数,父子
* 、母子、配偶等 (3)检查某两人之间是否是堂兄妹
*/
struct person{
char *name; /* 人的姓名 */
char sex; /* 性别,'M'表示男性,'F'表示女性 */
struct person *father; /* 该人的父亲 */
struct person *mother; /* 该人的母亲 */
struct person *mate; /* 该人的配偶 */
struct person *childs[CHILDREN]; /* 该人的孩子 */
};
/* [函数] 添加一个新人 */
struct person * newperson(char *name,char sex){
struct person *p = (struct person *)malloc(sizeof(struct person));
p->name = (char *)malloc(sizeof(name)+1);
strcpy(p->name,name);
p->sex = sex;
p->father = NULL;
p->mother = NULL;
p->mate = NULL;
int i = 0;
for(i = 0;i < CHILDREN;i++){
p->childs[i] = NULL;
}
return p;
};
/* [函数] 建立父子关系 */
void father_child(struct person *father,struct person *child){
int index;
for(index = 0;index < CHILDREN-1;index++) /* 寻找一个空缺的位置 */
if(father->childs[index] == NULL) /* 如果没有,则放到最后 */
break;
father->childs[index] = child;
child->father = father;
}
/* [函数] 建立母子关系 */
void mother_child(struct person *mother,struct person *child){
int index;
for(index = 0;index < CHILDREN-1;index++) /* 寻找一个空缺的位置 */
if(mother->childs[index] == NULL) /* 如果没有,则放到最后 */
break;
mother->childs[index] = child;
child->mother = mother;
}
/* [函数] mate 建立配偶关系 */
void mate(struct person *h,struct person *w){
/* 建立配偶关系 */
h->mate = w;
w->mate = h;
}
/**[函数] 判断是否为堂兄妹
* params:
* struct person *p1:被判断的人
* struct person *p2:被判断的人
* return:
* 0:不是堂兄妹关系
* 1:是堂兄妹关系
*/
int brothersinlaw(struct person *p1,struct person *p2)
{
struct person *f1,*f2;
if(p1 == NULL || p2 == NULL || p1 == p2) return 0;
if(p1->sex == p2->sex) return 0; /* 不可能是堂兄妹*/
f1 = p1->father;
f2 = p2->father;
if(f1 != NULL &&f1 == f1)
return 0; /* 是兄妹,不是堂兄妹 */
while(f1 != NULL && f2 != NULL && f1 != f2) /* 远亲 */
{
f1 = f1->father;
f2 = f2->father;
if(f1 != NULL && f2 != NULL && f1 == f2) return 1;
}
return 0;
}
/* [函数] 输出人物关系 */
void print_relate(struct person *p)
{
int index,i;
if(p->name == NULL)
return;
if(p->sex == 'M')
printf("%s is male.\n",p->name);
else
printf("%s is female.\n",p->name);
if(p->father != NULL)
printf("%s's father is %s.\n",p->name,p->father->name);
if(p->mother != NULL)
printf("%s's mother is %s.\n",p->name,p->mother->name);
if(p->mate != NULL)
if(p->sex == 'M')
printf("His wife is %s.\n",p->mate->name);
else
printf("Her husband is %s.\n",p->mate->name);
if(p->childs != NULL){
for(index = 0;index <CHILDREN-1;index++)
if(p->childs[index] == NULL)
break;
if(index > 0)
printf(" Children are : ");
for(i = 0;i < index;i++)
printf("%s\t",p->childs[i]->name);
}
printf("\n");
}
int main()
{
char *name[8]={"John","Kate","Maggie","Herry","Jason","Peter","Marry","Jenny"};
char male='M',female='F';
struct person *pGrandfather,*pFather1,*pFather2,*pMother1,*pMother2,*pSon,*pDaughter,*pCousin;
pGrandfather = newperson(name[0],male);
pFather1 = newperson(name[3],male);
pFather2 = newperson(name[4],male);
pMother1 = newperson(name[1],female);
pMother2 = newperson(name[2],female);
pSon = newperson(name[5],male);
pDaughter = newperson(name[6],female);
pCousin = newperson(name[7],female);
father_child(pGrandfather,pFather1);
father_child(pGrandfather,pFather2);
father_child(pFather1,pSon);
father_child(pFather1,pDaughter);
father_child(pFather2,pCousin);
mate(pFather1,pMother1);
mate(pFather2,pMother2);
mother_child(pMother1,pSon);
mother_child(pMother1,pDaughter);
mother_child(pMother2,pCousin);
/* 输出各种关系 */
print_relate(pGrandfather);
print_relate(pFather1);
print_relate(pFather2);
print_relate(pMother1);
print_relate(pMother2);
print_relate(pSon);
print_relate(pDaughter);
print_relate(pCousin);
if(!brothersinlaw(pDaughter,pCousin))
printf("%s and %s are not brothers (sisters) in law.\n",pDaughter->name,pCousin->name);
else
printf("%s and %s are brothers (sisters) in law.\n",pDaughter->name,pCousin->name);
if(!brothersinlaw(pSon,pCousin))
printf("%s and %s are not brothers (sisters) in law.\n",pSon->name,pCousin->name);
else
printf("%s and %s are brothers (sisters) in law.\n",pSon->name,pCousin->name);
if(!brothersinlaw(pSon,pDaughter))
printf("%s and %s are not brothers (sisters) in law.\n",pSon->name,pDaughter->name);
else
printf("%s and %s are brothers (sisters) in law.\n",pSon->name,pDaughter->name);
return 0;
}
~~~
总体来说,该实例并不难,并没有涉及到比较复杂的算法,其中稍微有些需要考虑的地方就是在判断两个人是否是堂兄妹的时候,用到了一点小方法,也不是很难。
下面我们来看一下程序的运行结果:
![这里写图片描述](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2016-05-24_5743c0acd746d.jpg "")
报数游戏
最后更新于:2022-04-01 14:29:12
(1):问题提出
设由n个人站成一个圈,分别编号1,2,3,4….n。从第一个人开始报数每次报数为m的人被从圈中推出,其后的人再次从1开始报数,重复上述过程, 直至所有人都从圈中退出。要求程序由用户输入整数m和n,求这n个人从圈中推出的先后顺序。
(2):解决思路
可利用链表求解这个问题,先由n形成一个有n个表元组成的环,其中n个表元依次置值1~n。然后,从环的第一个表元出发,连续掠过m-1个表元,第m-1个表元的后继表元是第m个表元,将该表元从环中退出。接着再次从下一个表元出发,重复以上过程,直至环中表元都退出为止。
(三):代码实现
~~~
#include <stdio.h>
#include <stdlib.h>
/**
* 设由n个人站成一个圈,分别编号1,2,3,4....n。从第一个人开始报数
* 每次报数为m的人被从圈中推出,其后的人再次从1开始报数,重复上述过程,
* 直至所有人都从圈中退出。要求程序由用户输入整数m和n,求这n个人从圈中
* 推出的先后顺序。
*
*/
//定义一个循环链表
struct LinkedList{
int number;
struct LinkedList *next;
};
//输出链表
void print(struct LinkedList *ll){
struct LinkedList *current = ll;
do{
printf("%d\t",current->number);
current = current->next;
}
while(current != ll);
printf("\n");
}
int main()
{
int m,n;
int i;
printf("Please input the m and n(dividded by ','):\n");
scanf("%d,%d",&n,&m);
struct LinkedList *pre = (struct LinkedList *)malloc(sizeof(struct LinkedList));
struct LinkedList *current = pre;
current->number = 1;
//分配内存并赋值
for(i = 2;i <= n;i++){
current->next = (struct LinkedList *)malloc(sizeof(struct LinkedList));
current = current->next;
current->number = i;
}
current->next = pre;
pre = current;
while(n){
for(i = 1; i < m;i++) //忽略那些没用的
pre = pre->next;
current = pre->next;
printf("%d\t",current->number); //打印出相关信息
pre->next = current->next; //删除打印出的信息
free(current);
n--;
}
return 0;
}
~~~
(四):相关知识
下面是我定义的一个关于循环链表的代码,大家可以看一下:
~~~
#include <stdio.h>
#include <stdlib.h>
//越界
#define OUT 0
//成功
#define SUCCESS 1
/**
* 设由n个人站成一个圈,分别编号1,2,3,4....n。从第一个人开始报数
* 每次报数为m的人被从圈中推出,其后的人再次从1开始报数,重复上述过程,
* 直至所有人都从圈中退出。要求程序由用户输入整数m和n,求这n个人从圈中
* 推出的先后顺序。
*
*/
//定义一个循环链表
struct LinkedList{
int number;
struct LinkedList *next;
};
//链表初始化
struct LinkedList * initLL(struct LinkedList *ll){
ll = (struct LinkedList *)malloc(sizeof(struct LinkedList));
ll->next = ll;
return ll;
}
//判断循环链表是否为空
int isEmpty(struct LinkedList *ll){
return ll->next == ll ? 1 : 0;
}
//返回链表中元素的个数
int size(struct LinkedList *ll){
struct LinkedList *current = ll;
int count = 0;
while(current->next != ll){
current = current->next;
count++;
}
return count;
}
//向链表中添加一个元素
void add(struct LinkedList *ll,int data){
struct LinkedList *temp = ll;
while(temp->next != ll)
temp = temp->next;
struct LinkedList *llAdd = (struct LinkedList *)malloc(sizeof(struct LinkedList));
llAdd->number = data;
temp->next = llAdd;
llAdd->next = ll;
}
//向指定位置添加元素
//即在position之后添加一个元素
int insert(struct LinkedList *ll,int position,int data){
if(size(ll) < position)
return OUT;
int i = 0;
struct LinkedList *temp = ll;
for(i = 0;i < position;i++){
temp = temp->next;
}
struct LinkedList *llAdd = (struct LinkedList *)malloc(sizeof(struct LinkedList));
llAdd->number = data;
llAdd->next = temp->next;
temp->next = llAdd;
return SUCCESS;
}
//删除指定位置的元素
int removeAt(struct LinkedList *ll,int position){
if(size(ll) < position)
return OUT;
struct LinkedList *current = ll;
struct LinkedList *pre ;
int i = 0;
for(i = 0;i < position;i++){
pre = current;
current = current->next;
}
//data = current->number;
printf("%d\t",current->number);
pre->next = current->next;
free(current);
return SUCCESS;
}
//输出链表
void print(struct LinkedList *ll){
struct LinkedList *current = ll->next;
while(current != ll){
printf("%d\t",current->number);
current = current->next;
}
printf("\n");
}
~~~
(五):运行结果
下面是程序的运行结果:
![这里写图片描述](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2016-05-24_5743c076705e0.jpg "")
使用“结构”统计学生成绩
最后更新于:2022-04-01 14:29:10
设学生信息包括学号,姓名和五门功课的成绩,要求编写输入输出
学生信息的函数。在输入一组学生信息后,以学生成绩的总分从高
到低顺序输出学生信息。
这个相对来说比较简单,可以创建一个学生的结构体,结构体里面有三个成员:学号,姓名和五门功课的成绩。下面请看一下我的整体代码。这个思路也比较简单,主要是为了练习使用结构体。
~~~
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define N 200
#define SCORES 5
#define NUMLEN 10
/**
* 设学生信息包括学号,姓名和五门功课的成绩,要求编写输入输出
* 学生信息的函数。在输入一组学生信息后,以学生成绩的总分从高
* 到低顺序输出学生信息。
*/
struct student{
char number[NUMLEN]; /* 学号 */
char *name; /* 学生姓名 */
int scores[SCORES]; /* 学生五门功课的成绩 */
};
struct student stus[N];
int order[N];
int total[N];
int readstu(struct student *stu){
int len,j;
char buf[120]; //缓冲区
printf("Number : ");
if(scanf("%s",buf) == 1){
strncpy(stu->number,buf,NUMLEN-1);
}else{
return 0; //ctrl+z退出
}
printf("Name : ");
if(scanf("%s",buf) == 1){
len = strlen(buf);
stu->name = (char *)malloc(len+1);
strcpy(stu->name,buf);
}else{
return 0;
}
printf("Scores : ");
for(j = 0;j < SCORES;j++)
if(scanf("%d",stu->scores+j) != 1)
break;
if(j == 0){ //一个成绩也没有录入,清空name所占有的内存
free(stu->name);
return 0;
}
for(;j<SCORES;j++)
stu->scores[j] = 0;
return 1;
}
/* 输出学生信息 */
void writeStu(struct student *stu){
int i;
printf("Number : %s\n",stu->number);
printf("Name : %s\n",stu->name);
printf("Scores : ");
for(i = 0;i < SCORES;i++)
printf("%4d ",stu->scores[i]);
printf("\n\n");
}
int main()
{
int n,i,j,t;
//获取学生信息
for(n = 0; readstu(stus+n); n++);
for(i = 0;i < n;i++){
order[i] = i;
for(t = 0,j = 0;j < SCORES;j++){
t += stus[i].scores[j];
}
total[i] = t;
}
//冒泡排序输出
for(i = 0;i < n;i++){
for(j = 0;j < n-1;j++){
if(total[order[j]] < total[order[j+1]]){
//交换
t = order[j];
order[j] = order[j+1];
order[j+1] = t;
}
}
}
for(j = 0;j <n;j++){
writeStu(stus+order[j]);
}
return 0;
}
~~~
下面是我的输出的结果:
![这里写图片描述](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2016-05-24_5743c07659f9d.jpg "")
扑克牌的结构定义
最后更新于:2022-04-01 14:29:08
使用结构定义一副扑克牌,并对变量赋值
扑克牌有四种花色:草花,方块,红心和黑桃,可将花色说明为枚举类型。扑克牌类型为结构类型,包含两个成分:分别存储牌的花色和牌的面值,其中面值为字符数组。
下面是代码的实现部分:
~~~
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
/**
* 使用结构定义一副扑克牌,
* 并对变量赋值
*
* 扑克牌有四种花色:草花,方块,红心
* 和黑桃,可将花色说明为枚举类型。扑克牌类型
* 为结构类型,包含两个成分:分别存储
* 牌的花色和牌的面值,其中面值为字符数组
*/
enum suits{CLUBS,DIAMONDS,HEARTS,SPADES};
/**纸牌结构 **/
struct card{
enum suits suit;
char value[3];
};
/**52张牌 **/
struct card cards[52];
/**纸牌的面值 **/
char values[][3] = {"A","2","3","4","5","6",
"7","8","9","10","J","Q","K"};
/**纸牌类型名称 **/
char names[][10] = {"CLUBS","DIAMONDS","HEARTS","SPADES"};
int main()
{
int i,j;
enum suits s;
for(i = 0;i < 13;i++){
for(s = CLUBS;s <= SPADES;s++){
j = i * 4 + s;
cards[j].suit = s;
strcpy(cards[j].value,values[i]);
}
}
for(j = 1;j <= 52;j++){
printf("<%s\t%s>\t",names[cards[j].suit],cards[j].value);
if(j % 4 == 0){
printf("\n");
}
}
return 0;
}
~~~
下面是程序的输出结果:
![这里写图片描述](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2016-05-24_5743c07645aed.jpg "")
总的来说,这个程序是相对比较简单的,在这里,我们学习使用了结构的定义,以及enum枚举的使用方法。
在实际问题中,有些变量的取值被限定在一个有限的范围内。例如一个星期有7天,一年只有12个月等,这些都可以使用枚举enum来定义。需要说明的是,枚举类型是一种基本数据类型,而不是一种构造结构。
通讯录的输入输出
最后更新于:2022-04-01 14:29:05
在实际问题中,一组数据往往具有不同的数据类型。例如,在学生登记表中,姓名为字符型,学号为整型或字符型,年龄为整型,性别为字符型,成绩为整型或实数型别,显然,不能使用一个数组来存放这一组数据。因为数组中各个元素的类型和长度都必须一致,以便于编译系统处理。为了解决这个问题,C语言中给出了另一种构造数据类型–结构。他相当于其他高级语言中的记录。
“结构”是一种构造类型,他是由若干“成员”组成的。每一个成员可以是一个基本数据类型或者又是一个构造类型。结构是一种“构造”而成的数据类型,在说明和使用之前先定义它,也就是构造它。就像是定义函数一样。
1:结构的定义
定义一个结构的一般形式为:
struct 结构名
{
成员列表
};
2:结构类型变量的说明
说明结构变量有3中方法,以结构stu为例。
~~~
struct stu
{
int num;
char name[20];
char sex;
float score;
};
//说明结构变量
struct stu boy1,boy2;
~~~
说明变量boy1和boy2为stu结构类型。也可以使用宏定义用一个符号常量来表示一个结构类型,例如
~~~
#define STU struct stu
STU
{
int num;
char name[20];
char sex;
float score;
};
STU boy1,boy2;
~~~
还可以在定义结构类型的同时说明结构变量,例如:
~~~
struct stu
{
int num;
char name[20];
char sex;
float score;
} boy1,boy2;
~~~
或者是直接说明结构变量,例如
~~~
struct
{
int num;
char name[20];
char sex;
float score;
}boy1,boy2;
~~~
注意:
如果结构变量是全局变量或为静态变量,则可以对它进行 初始化赋值。对局部或自动结构变量不能进行初始化赋值。
3:结构数组
继续使用上面stu的例子:
struct stu boys[20];
4:结构指针变量
当使用一个指针变量指向一个结构变量时,称之为结构指针变量。结构变量中的值是所指向的结构变量的首地址。通过结构指针即可访问该结构
变量,这与数组指针和函数指针的情况是相同的。结构指针变量说明的一般形式为:
struct 结构名 *结构指针变量名
例如,如果要说明一个指向stu的指针变量pstu,可写为:
struct stu *pstu;
当然,也可以在定义stu结构的时候同时说明pstu。与前面变量的声明相同。结构指针变量必须要先赋值后才能使用。赋值是把结构变量的首地址赋予该指针变量,不能把结构名赋予该指针变量,如过boy是被说明为stu类型的结构变量,则”pstu=&boy”是正确的,但是”pstu=&stu”是错误的。
结构名和结构变量是两个不同的概念,不能混淆。结构名只能表示一个结构形式,编译系统并不对他分配空间。只有当变量说明为这种类型的结构时,才对该变量分配内存空间。因此”&stu”的写法是错误的,不可能去取一个结构名的首地址。有了结构指针变量,就能更方便的访问结构变量的各个成员。
程序访问的一般形式为:(*结构指针变量).成员名 或为:
结构指针变量->成员名
例如”(*pstu).num”或者”pstu->num”。
应该注意(*pstu)两侧的括号不可少,因为成员符号“.”的优先级高于”*“。如果去掉括号协作*pstu.num,就等效于”*(pstu.num)”,这样意义就不对了。
5:结构指针变量作为函数参数
在ANSI C标准中允许使用结构变量作为函数参数进行整体传送。但是这种传送要将全部成员逐个传送,特别是成员为数组时将会使传送的时间和空间开销很大,严重的降低了程序的效率。因此最好的办法就是使用指针,即用指针变量作为函数参数进行传送,由于实参传向星灿的只是地址,从而减少了时间和空间的开销。
在本例中,假设一个通讯录由以下几项数据信息组成
数据项 类型
姓名 字符串
地址 字符串
邮政编码 字符串
电话号码 字符串
下面请看一下代码的实现:
~~~
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define ZIPLEN 10
#define PHONLEN 10
struct addr{
char *name; /* 姓名 */
char *address; /* 地址 */
char zip[ZIPLEN]; /* 邮编 */
char phone[PHONLEN]; /* 手机号码 */
};
int readaddr(struct addr *dpt);
int writeaddr(struct addr *dpt);
/**
* 编制一个包含姓名,地址,邮编和电话的通讯录
* 输入输出函数。
*/
int main()
{
struct addr p[1];
int i,j;
for(i=0;readaddr(p+i);i++);
for(j = 0;j < i;j++)
writeaddr(p+j);
puts("Press any key to quit...\n");
getch();
return 0;
}
/**
* 向结构中的成员赋值
*
*/
int readaddr(struct addr *dpt)
{
int len;
char buf[120]; //输入字符串的缓冲区
printf("Please input the Name:\n");
if(scanf("%s",buf)==1){
len = strlen(buf);
dpt->name = (char *)malloc(len+1);
strcpy(dpt->name,buf);
}else return 0;
printf("Please input the Address:\n");
if(scanf("%s",buf) == 1){
len = strlen(buf);
dpt->address = (char *)malloc(len+1);
strcpy(dpt->address,buf);
}else{
free(dpt->name);
return 0;
}
printf("Please input the Zip:\n");
if(scanf("%s",buf) == 1){
strncpy(dpt->zip,buf,ZIPLEN-1);
}else{
free(dpt->name);
free(dpt->address);
return 0;
}
printf("Please input the Phone:\n");
if(scanf("%s",buf) == 1){
strncpy(dpt->phone,buf,PHONLEN-1);
}else{
free(dpt->name);
free(dpt->address);
return 0;
}
return 1;
}
/**
* 输出通讯录
*/
int writeaddr(struct addr *dpt)
{
printf("Name : %s\n",dpt->name); /* 输出姓名 */
printf("Address : %s\n",dpt->address); /* 输出地址 */
printf("Zip : %s\n",dpt->zip); /* 输出邮编 */
printf("Phone : %s\n",dpt->phone); /* 输出手机号 */
}
~~~
下面是运行结果:
![这里写图片描述](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2016-05-24_5743c076269dc.jpg "")
注意:关于动态内存分配问题:
在数组中,数组的长度是预先定义好的,在整个程序中固定不变。C语言不允许动态数组类型。例如”int n;scanf(“%d”,n);int a[n];”,这是错误的。但是在实际编译过程中,往往会发生这种情况,即所需的内存空间取决于实际输入的数据,而无法预先确定。对于这种问题,用数组的办法很难解决。为了解决上述问题,C语言提供了一些内存管理函数,这些内存管理函数可以按照需要动态分配内存空间,也可以把不再使用的空间收回待用。常用的内存管理函数有3个:
1:分配内存空间函数malloc。调用形式
(类型说明符 *)malloc(size);
在内存的动态存储区中分配一块长度为”size”字节的连续区域。函数的返回值为该区域的首地址。
2:分配内存空间函数 calloc。calloc也用于分配内存空间,调用形式:
(类型说明符 *)calloc(n,size);
在内存动态存储区中分配n快长度为”size”字节的连续区域。函数的返回值为该区域的首地址。
3:释放内存空间函数free.调用形式
free(void *ptr);
释放ptr所指向的一块内存区域,ptr是一个任意类型的指针变量,他指向被释放区域的首地址。被释放区域应是由malloc或calloc函数所分配的区域。
C实例–判断一个字符串是否是回文数
最后更新于:2022-04-01 14:29:03
回文是指顺读和反读内容均相同的字符串,例如”121”,”ABBA”,”X”等。本实例将编写函数判断字符串是否是回文。
引入两个指针变量,开始时,两个指针分别指向字符串的首末字符,当两个指针所指字符相等时,两个指针分别向后和向前移动一个字符位置,并继续比较,直到两个指针相遇,说明该字符串是回文,如果比较过程中发现两个指针指向的字符不相等,则判断该字符串不是回文。
下面是代码的实现部分:
~~~
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define N 20
int Cycle(char *s);
/**
* 回文是指顺读和反读内容均相同的字符串,例如"121","ABBA","X"等。
* 本实例将编写函数判断字符串是否是回文。
*
*/
int main()
{
char s[N];
while(1){
printf("Please input the string you want to judge(input ^ to quit):\n");
scanf("%s",&s);
if(s[0] == '^'){
break;
}
if(Cycle(s)){
printf("%s is a cycle string!\n",s);
}else{
printf("%s is not a cycle string!\n",s);
}
}
return 0;
}
/**
* 判断字符串s是否是回文
*
* param:
* char *s: 被判断的字符串
* return:
* 0: 表示字符串s不是回文数
* 非零: 表示字符串s是回文数
*/
int Cycle(char *s){
char *h,*t;
for(h = s,t = s + strlen(s) - 1;t > h;h++,t--)
if(*h != *t) break;
return t <= h;
}
~~~
下面是程序的运行结果:
![这里写图片描述](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2016-05-24_5743c0761002e.jpg "")
在做这个实例的时候,让我想到了之前有一个实例是判断一个数是否是回文数,是这样做的,假设一个数n=232,从各位数字开始,分别为2,3,2;这些数字分别乘以100,10,1最后相加,比较和原来的数是否相等,就能判断该数书否是回文数字了。
C实现字符排列
最后更新于:2022-04-01 14:29:01
用已知字符串s中的字符,生成由其中n个字符组成的所有字符的排列。设n小于字符串s的字符个数,其中s中的字符在每个排列中最多出现一次。 例如,对于s[]=”abc”,n=2,则所有字符的排列有:ba,ca,ab,cb,ac,bc。
算法思想:
使用递归完成该实例。
- 举个例子:
- s = “abc”,n=2
- 则第一个perm(n,s),即perm(2,”abc”);
- 首先需要判断w中的字符个数是否满足,n=2>1,表示还没有满足
- 首先,从s的第一个元素开始,s[1] = ‘a’;
- 填充到w中,w[n-1]即,w[1] = ‘a’;
- 紧接着,进行一些调整,使得s1 = bc,n=1
- 进行同样的perm,即perm(1,”bc”);同样先进行判断
- 选择b填充到w中,在进入perm(0,”c”),判断输出
- 接着,回到上一层,perm(1,”bc”),再选择字符”c”进入w
- 选择c进入w之后,进行一些调整,将s1调整成这样一个字符串s1=”cb”,
- 这样进入perm(0,”b”),判断输出.
*
- 接着,进入第一层,由于ba,ca都已经输出完毕,第一个元素从b开始进行选择
- 首先将b放入w中,即w[1] = ‘b’;接着进行一些调整,将s1调整为s1 = “bac”;
- 进入perm(1,”ac”);
- 以此方式进行递归,完成。
下面是代码实现部分:
~~~
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define N 20
char w[N];
void perm(int n,char *s);
/**
* 用已知字符串s中的字符,生成由其中n个字符组成的所有字符的排列。
* 设n小于字符串s的字符个数,其中s中的字符在每个排列中最多出现一次。
* 例如,对于s[]="abc",n=2,则所有字符的排列有:ba,ca,ab,cb,ac,bc。
*/
int main()
{
char s[N];
int n;
printf("Please enter the char array:\n");
scanf("%s",&s);
printf("Please number:\n");
scanf("%d",&n);
perm(n,s); //调用排列函数
return 0;
}
/**
* 举个例子:
* s = "abc",n=2
* 则第一个perm(n,s),即perm(2,"abc");
* 首先需要判断w中的字符个数是否满足,n=2>1,表示还没有满足
* 首先,从s的第一个元素开始,s[1] = 'a';
* 填充到w中,w[n-1]即,w[1] = 'a';
* 紧接着,进行一些调整,使得s1 = bc,n=1
* 进行同样的perm,即perm(1,"bc");同样先进行判断
* 选择b填充到w中,在进入perm(0,"c"),判断输出
* 接着,回到上一层,perm(1,"bc"),再选择字符"c"进入w
* 选择c进入w之后,进行一些调整,将s1调整成这样一个字符串s1="cb",
* 这样进入perm(0,"b"),判断输出.
*
* 接着,进入第一层,由于ba,ca都已经输出完毕,第一个元素从b开始进行选择
* 首先将b放入w中,即w[1] = 'b';接着进行一些调整,将s1调整为s1 = "bac";
* 进入perm(1,"ac");
* 以此方式进行递归,完成。
*/
void perm(int n,char *s){
if(n < 1){
//如果n小于1,表示w中的长度已经达到需要的长度
printf("%s\n",w);
return;
}else{
char s1[N]; //临时变量存储
strcpy(s1,s);
int i;
for(i = 0;*(s1+i);i++){
//从s1中选择一个字符放入w对应的位置中
*(w+n-1) = *(s1+i);
//将从s1中被选择的字符替换成第一个字符
*(s1+i) = *s1;
//将第一个字符换成被选择的字符
*s1 = *(w+n-1);
perm(n-1,s1+1);
}
}
}
~~~
下面是程序的运行结果:
![这里写图片描述](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2016-05-24_5743c075edd44.jpg "")
总体来说,这个算法的思路还是比较简单的。
C实现字符行排版
最后更新于:2022-04-01 14:28:58
将字符行内单字之间的空白符平均分配插入到单字之间,以实现字符行排版。首先要统计字符行内单字个数,字符行内的空白字符数。然后计算单字之间 应该平均分配的空白字符数,另外约定多余的空白字符插在前面的单字间隔中前面的每个间隔多一个空白符,插完为止。
下面是我的代码的实现部分,这个字符行排版代码比较简答,其中的,实现统计单词个数的方法还是值得大家学习一下的。
~~~
#include <stdio.h>
#define N 80
/**
* @brief main
* 将字符行内单字之间的空白符平均分配插入到单字之间,
* 以实现字符行排版。
*
* 首先要统计字符行内单字个数,字符行内的空白字符数。然后计算单字之间
* 应该平均分配的空白字符数,另外约定多余的空白字符插在前面的单字间隔中
* 前面的每个间隔多一个空白符,插完为止。
* @return
*/
edit(char *s)
{
int i,sp,w,inw,v,r;
char buf[N],*str;
for(inw=sp=w=i=0;s[i];i++)
{
if(s[i]==' ')
{ /* 统计空白个数*/
sp++;
inw=0; /* 置空白符状态*/
}
else if(!inw)
{
w++; /* 统计单字个数*/
inw=1; /* 置单字状态*/
}
}
if(w<=1)
return; /* 单字数不超过1, 不排版 */
v=sp/(w-1); /* 每个间隔平均空白符 */
r=sp%(w-1); /* 多余的空白符 */
strcpy(buf,s);
for(str=buf;;)
{
while(*str==' ')str++; /* 掠过空白符 */
for(;*str&&*str!=' ';) /* 复制单字 */
*s++=*str++;
if(--w==0)
return; /* 全部单字复制完毕,返回 */
for(i=0;i<v;i++)
*s++=' '; /* 插入间隔空白符 */
if(r)
{
*s++=' '; /* 插入一个多余空白符 */
r--;
}
}
}
int main() /* 用于测试edit函数 */
{
char buff[N];
puts("This is a typeset program!\nPlease input a character line:\n");
gets(buff);
edit(buff);
printf("\nThe character line after typeset is:\n\n%s\n",buff);
puts("\n Press any key to quit...\n ");
getch();
return 0;
}
~~~
下面是我的程序的运行结果:
![这里写图片描述](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2016-05-24_5743c075d9bbe.jpg "")
从键盘读入实数
最后更新于:2022-04-01 14:28:56
编制一个从键盘读入实数的函数`readreal(double *rp)`。函数将读入的实数字符列换成实数后,利用指针参数rp,将实数存于指针所指向的变量`*rp`。
解析:
函数在返回之前,将最后读入的结束实数字符列的字符返还给系统,以便随后读字符时能再次读入该字符。函数若能正常读入实数,函数返回整数1,如果函数在读入过程中,未遇到数字符之前,遇到不能构成数字的情况,函数返回-1,表示为读到实数。
在输入实数时,在实数之前可以有一个数不定的空白类字符,组成实数的字符列有数的符号字符,实数的整数部分,小数点和实数的小数部分,其中,某些部分可以缺省。设实数字符列有以下几种可能形式:
数符 整数部分
数符 整数部分
数符 整数部分.小数部分
数符 .小数部分
其中数符或为空,或为’+’,或为’-‘,分别代表不带符号,带正号,带负号。整数部分和小数部分至少要有一个数字符组成。
上述实数形式说明,在实数转换过程中,同一字符在不同情况下会有不同的意义。为标记当前实数转换的不同情况,程序引入状态变量,有状态变量的不同值代表当前实数转换过程中的不同情况。
共有以下多种不同的情况:正准备开始转换,转换了数的符号字符,正在转换实数的整数部分,正在转换实数的小数部分,发现输入错误,转换正常结束。设状态变量为0表示正准备开始转换,还未遇到任何与实数有关的字符;1表示已经遇到数的符号字符;2表示正在转换实数的整数部分,3表示在未遇到数字字符之前先遇到小数点;4表示在转换整数部分之后遇到小数点;5表示转换发现错误,6表示转换正常结束。
读函数另外有两张表,一张是转换函数表,一张是状态表。函数反复读入字符,将字符分类,根据当前状态和当前字符类调用对应转换函数。
下面是程序的实现部分:
~~~
#include <stdio.h>
#define ERR 5
#define OK 6
int status;
double result,sig,scale;
/*
* 处理数的符号函数
*/
int sign(int c){
if(c = '-') /* 若为负号,取负 */
sig=-sig;
}
/**
* @brief integer 转换整数部分
* @param c 要被转换的整数位
* @return 返回成功与否
*/
int integer(int c){
result = result * 10.0 + c - '0';
}
/**
* @brief decimal 转换小数部分
* @param c 要被转换的小数位
* @return 返回成功与否
*/
int decimal(int c){
result += (c -'0') * scale;
scale /= 10;
}
/* 状态表 */
/*
* 0 - 正准备开始转换,还未遇到任何与实数有关的字符
* 1 - 已遇数的符号字符
* 2 - 正在转换实数的整数部分
* 3 - 在未遇数字字符之前先遇到小数点
* 4 - 在转换整数部分之后先遇到小数点
* 5 - 表示转换发现错误
* 6 - 转换正常结束
*/
int statbl[][4]={
{1,2,3,ERR},
{ERR,2,3,ERR},
{OK,2,4,OK},
{ERR,4,ERR,ERR},
{OK,4,OK,OK}
};
/* 转换函数表 */
int (*funtbl[][4])() = {
{sign,integer,NULL,NULL},
{NULL,integer,NULL,NULL},
{NULL,integer,NULL,NULL},
{NULL,decimal,NULL,NULL},
{NULL,decimal,NULL,NULL}
};
/**
* @brief readreal 用于对输入的字符串转换成浮点数
* @param dp 转换后的浮点数
* @return 返回是否转换成功
*/
int readreal(double *dp){
int c,ckind;
sig = 1.0;
result = 0.0;
scale = 0.1;
while((c=getchar()) == ' ' || c == '\n' || c == '\t'); //跳过这些字符
status = 0; //重置初始状态
for(;;){
/* 分类当前字符 */
if(c == '+' || c== '-') ckind = 0; /* 数的符号字符 */
else if(c >= '0' && c <= '9') ckind = 1; /* 数字符 */
else if(c == '.') ckind = 2; /* 小数点 */
else ckind = 3; /* 其他字符 */
if(funtbl[status][ckind]){
(*funtbl[status][ckind])(c); /* 执行相应的转换函数 */
}
status = statbl[status][ckind]; /* 设置新的状态 */
if(status == ERR || status == OK) break; /*结束,出错或成功 */
c=getchar();
}
ungetc(c,stdin); /* 归还数的结束符*/
if(status == OK){
*dp = result * sig;
return 1;
}
return -1;
}
int main()
{
double x;
printf("Please input real numbers:\n");
while(readreal(&x) == 1)
printf("The real number is : %f\n",x);
return 0;
}
~~~
下面是我的程序的运行结果:
![这里写图片描述](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2016-05-24_5743c075c3bca.jpg "")
这个程序刚开始的时候,我的思路是,从第1个元素开始遍历,遍历过程中,在遇到”.”之前,类似于上面integer()函数的实现方式,当遇到点之后,就类似于上面decimal()函数的实现方式,但是看了作者的源码之后,发现需要学习一个做着的思路,思路敏捷,代码整洁,需要好好学习。
字符替换
最后更新于:2022-04-01 14:28:54
编制一个字符替换函数rep(char *s,char *s1,char *s2),实现将已知字符串s中所有属于字符串s1中的字符都用字符串s2中的对应字符代替。这里使用指针实现。
-
举个例子:
- char s[] = “ABCABC”;
- char s1[] = “AB”;
-
char s2[] = “XY”;
-
运行该函数之后,变为”XBYXBY”
那么可以这么想,s1和s2分别位于两个数组中,从s的第一个字符开始,寻找s1中是否有与该元素相等的字符,如果存在该字符,就将s2中相应位置的字符替换成s中的字符。
后面我们使用指针实现的函数也是基于这个道理的。
下面附上我的实现代码:
~~~
#include <stdio.h>
#define MAX 100
void rep(char *s,char *s1,char *s2);
/**
* @brief main 编制一个字符替换函数rep(char *s,char *s1,char *s2),
* 实现将已知字符串s中所有属于字符串s1中的字符都用字符串s2中的对应字符
* 代替
* 例如
* char s[] = "ABCABC";
* char s1[] = "AB";
* char s2[] = "XY";
*
* 运行该函数之后,变为"XBYXBY"
*
* @return
*/
int main(void)
{
char s[MAX],s1[MAX],s2[MAX];
printf("Please enter the s array:\n");
scanf("%s",&s);
printf("Please enter the s1 array:\n");
scanf("%s",&s1);
printf("Please enter the s2 array:\n");
scanf("%s",&s2);
rep(s,s1,s2);
printf("After rep,the array s is:\n");
printf("%s\t",s);
return 0;
}
/**
* @brief rep 将字符串s中所有属于字符串s1中的字符都用字符串s2中的对应字符代替
* @param s 源字符串
* @param s1 要被替换的字符
* @param s2 替换的字符
*/
void rep(char *s,char *s1,char *s2){
char *p;
for(;*s;s++){
for(p = s1;*p && *p!=*s;p++);
if(*p){
/**
* 这个地方处理的比较好
* p-s1为偏移量,当s2加上相应的偏移量之后;
* 就是对应的要被替换的字符
*/
*s = *(p-s1+s2);
}
}
}
~~~
下面是我的程序的运行结果:
![这里写图片描述](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2016-05-24_5743c075acbc8.jpg "")
整数转换成罗马数字
最后更新于:2022-04-01 14:28:52
编写一个将整数n(1 <= n <= 9999)转换成罗马数字。
- 整数n(1<=n<=9999)与罗马数字表示有以下对应关系
- 1000 - m,有几个1000就有几个m对应
- 900 - 两个字符cm
- 500 - 一个字符d
- 400 - 两个字符cd
- 100 - 一个字符c,有几个100就用几个c表示
- 90 - 两个字符xc
- 50 - 一个字符l
- 40 - 两个字符xl
- 10 - 一个字符x,有一个10就用几个x
- 9 - 用两个字符ix表示
- 5 - 用一个字符v来表示
- 4 - 用两个字符iv表示
- 1 - 用一个字符i表示,有几个1就用几个i
假如说我们有一个数字22,那么它转换的方式为22-10=12>=0;
则肯定先有一个x,接着12-10=2>=0;则接着在x后面加上x 变为xx;2-1=1>=0;则肯定后面还需要添加一个i变为xxi,1-1=0>=0;后面还要添加一个i变为xxii。
这样我们可以这样做,将对应的罗马数字和对应的数字放到两个二维数组中一一对应。
~~~
char *roman[ROW][COLUMN] = {
{"m","m","m","m"},
{"cm","d","cd","c"},
{"xc","l","xl","x"},
{"ix","v","iv","i"}
};
int num[ROW][COLUMN] = {
{1000,1000,1000,1000},
{900,500,400,100},
{90,50,40,10},
{9,5,4,1}
};
~~~
这样每一个数字进入之后,从数字数组的第一个元素开始,进行减法,如果差大于等于0,接着对这个数字进行减法操作,如果小于0了,则进入下一个数字进行同样的减法操作,每次差大于等于0的时候,在后面添加上对应的罗马数字。则转换算法应该是这样的。
~~~
/**
* @brief toRoman 将数字转换成罗马数字保存到数组rom中
* @param number 要被转换的数字
* @param rom 将转换后的罗马数字保存到rom数组中
*/
void toRoman(int number,char rom[]){
int temp = number;
int i,j;
rom[0]='\0';
for(i = 0;i < ROW;i++){
for(j = 0;j < COLUMN;j++){
while((temp-num[i][j]) >= 0){
strcat(rom,roman[i][j]);
temp = temp-num[i][j];
}
}
}
}
~~~
好了,主体函数已经有了,现在附上我的整体的代码:
~~~
#include <stdio.h>
#include <string.h>
#define ROW 4
#define COLUMN 4
void toRoman(int number,char rom[]);
/**
* @brief main 编写一个将整数(1 <= x <= 9999)转化成对应的罗马数字的程序
* @return
*/
/**
* 整数n(1<=n<=9999)与罗马数字表示有以下对应关系
* 1000 - m,有几个1000就有几个m对应
* 900 - 两个字符cm
* 500 - 一个字符d
* 400 - 两个字符cd
* 100 - 一个字符c,有几个100就用几个c表示
* 90 - 两个字符xc
* 50 - 一个字符l
* 40 - 两个字符xl
* 10 - 一个字符x,有一个10就用几个x
* 9 - 用两个字符ix表示
* 5 - 用一个字符v来表示
* 4 - 用两个字符iv表示
* 1 - 用一个字符i表示,有几个1就用几个i
*
*/
/**
* 用两个二维数组保存整数和罗马数字的
* 对应关系
*/
char *roman[ROW][COLUMN] = {
{"m","m","m","m"},
{"cm","d","cd","c"},
{"xc","l","xl","x"},
{"ix","v","iv","i"}
};
int num[ROW][COLUMN] = {
{1000,1000,1000,1000},
{900,500,400,100},
{90,50,40,10},
{9,5,4,1}
};
int main(int argc,char *argv[])
{
int low,high;
if(argc < 2){
printf("Please enter the range of the numbers.\n");
}else if(argc == 2){
low = 1;
high = atoi(argv[1]);
}else if(argc == 3){
low = atoi(argv[1]);
high = atoi(argv[2]);
}else{
printf("There is more params!!\n");
}
int i = low;
for(i = low;i <= high;i++){
char rom[25];
toRoman(i,rom);
printf("%d => %s\n",i,rom);
}
return 0;
}
/**
* @brief toRoman 将数字转换成罗马数字保存到数组rom中
* @param number 要被转换的数字
* @param rom 将转换后的罗马数字保存到rom数组中
*/
void toRoman(int number,char rom[]){
int temp = number;
int i,j;
rom[0]='\0';
for(i = 0;i < ROW;i++){
for(j = 0;j < COLUMN;j++){
while((temp-num[i][j]) >= 0){
strcat(rom,roman[i][j]);
temp = temp-num[i][j];
}
}
}
}
~~~
下面是我的程序的输出结果:
![这里写图片描述](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2016-05-24_5743c075916d7.jpg "")
寻找相同元素的指针
最后更新于:2022-04-01 14:28:49
此实例的要求是在两个已经摆好顺序的数组寻找第一个相同的元素在第一个数组中的指针。
这个实例的思想比较好,如果我来做的话,就是先从第一个数组的第一个元素开始,每次取出一个元素,与第二个数组的每一个元素进行比较,当元素值相等的时候,返回元素的指针。
但是在此实例中,使用了另外一种思想,在我看来降低了程序的时间复杂度。其思想为:由于两个数组都已经排好顺序,则分别从两个数组的第一个元素开始,比较大小,将较小的元素的数组的位置指向下一个,知道找到相同的元素为止。
下面我程序的实现部分:
~~~
#include <stdio.h>
#define NULL 0
/**
* 在已知两个从小到大的有序数组中寻找出现的相同的
* 元素在第一个数组中的指针
*
* 思想:
* 由于两个数组是已经拍好顺序的,所以可以这样:
* 从两个数组的第一个元素开始,比较两个数组的元素
* 较小的元素的数组位置向下移动,知道找到相等的元素
*/
/**
* @brief search 找到两个数组中第一个相同的元素的指针
* @param array1 第一个数组
* @param n1 第一个数组的长度
* @param array2 第二个数组
* @param n2 第二个数组的长度
* @return 返回两个数组第一个相同元素在第一个数组中的指针
*/
int search(int *array1,int n1,int *array2,int n2){
int *p1 = array1;
int *p2 = array2;
while(p1 < array1+n1 && p2 < array2+n2){
if(*p1 < *p2){
printf("*p1 < *p2\n");
p1++;
}else if(*p1 > *p2){
printf("*p1 > *p2\n");
p2++;
}else{
printf("*p1 = *p2\n");
return p1;
}
}
return NULL;
}
int main(void)
{
int n1,n2; //The length of the first and the second array
int i;
printf("Please enter the length of the first array:\n");
scanf("%d",&n1);
int array1[n1];
printf("Please enter the first array:\n");
for(i = 0;i < n1;i++)
scanf("%d",&array1[i]);
printf("Please enter the length of the second array:\n");
scanf("%d",&n2);
int array2[n2];
printf("Please enter the second array:\n");
for(i = 0;i < n1;i++)
scanf("%d",&array2[i]);
printf("The first array is :\n");
for(i = 0;i < n1;i++)
printf("%d\t",array1[i]);
printf("\n");
printf("The second array is :\n");
for(i = 0;i < n1;i++)
printf("%d\t",array2[i]);
printf("\n");
int p = search(array1,n1,array2,n2);
if(p)
printf("The pointer of the first same element in the first array is:\n%d",p);
else
printf("not found!!\n");
return 0;
}
~~~
下面是我的程序的运行结果:
![这里写图片描述](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2016-05-24_5743c0757ac8b.jpg "")
寻找指定元素
最后更新于:2022-04-01 14:28:47
在已知数表中找出第一个与指定值相等的元素的下标和指针。这个实例还是比价简单的。
我的思路是,首先创建一个struct结构,该结构中有两个成员变量,一个是数组元素的下标,一个是数组元素的指针值,当程序进程查找的时候,将找到的结果保存到该结构上。下面是我的程序的实现部分:
~~~
#include <stdio.h>
#define SIZE 100
/**
* @brief The element struct
* 元素的结构,包括元素的下标和元素的指针
*/
struct element{
int subScript;
int p;
};
/**
* @brief Search 在数组array中,寻找第一个与key相等的元素的下标和指针
* @param key 要寻找第一个与key相等的元素
* @param array 要被寻找的数组
* @param n 数组array中有几个元素
* @return 返回含有元素下标和指针的结构
*/
struct element Search(int key,int array[],int n){
int i = 0;
struct element ele;
for(i = 0;i < n;i++){
if(key == array[i]){
ele.subScript = i;
ele.p = &array[i];
return ele;
}
}
return ele;
}
/**
* 在已知数表中找出第一个与指定值相等的元素的下标
* 和指针
* @brief main
* @return
*/
int main(void)
{
int n;
int i;
int key;
int array[SIZE];
printf("Please enter the length of the array:\n");
scanf("%d",&n);
printf("Please enter the lements of the array:\n");
for(i = 0;i < n;i++){
scanf("%d",&array[i]);
}
printf("Please enter the key for searching:\n");
scanf("%d",&key);
struct element searched = Search(key,array,n);
//查看是否已经查到匹配的元素
if(searched.p == 0){
printf("There is no element equals to key!!\n");
}else{
printf("The subscript of the element is %d.\n",searched.subScript);
printf("The pointer of the element is %d.\n",searched.p);
}
return 0;
}
~~~
下面是我的程序运行的截图:
![这里写图片描述](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2016-05-24_5743c07566375.jpg "")
指向数组的指针
最后更新于:2022-04-01 14:28:45
指向数组的指针变量成为数组指针变量。一个数组是由连续的一块内存单元组成的。数组名就是这块连续内存单元的首地址。
该实例我们实现了使用数组的指针引用数组,利用数组名以及下标引用数组等。
其中,使用数组的指针和数组的下标来遍历数组的时候可能不太容易理解,但是我已经在注释中说明清楚了。
下面附上我的代码:
~~~
#include <stdio.h>
/**
* 本实例实现通过指向数组的指针引用数组,
* 利用数组名以及下标引用数组等
* @brief main
* @return
*/
int a[]={1,2,3,4,5};
#define N sizeof(a)/sizeof(a[0])
int main(void)
{
int j; //游标变量
int *p; //指针变量
//利用数组名和下标顺序访问数组元素
for(j = 0;j < N;j++){
printf("a[%d]\t= %d\t",j,a[j]);
}
printf("\n");
//让指针顺序指向数组的各元素,遍历数组
for(p = a;p < a+N;p++){
printf("*p\t= %d\t",*p);
}
printf("\n");
//指针和游标变量结合,改变游标变量遍历数组
for(p = a,j = 0;p+j<a+N;j++){
printf("*(p+%d)\t= %d\t",j,*(p+j));
}
printf("\n");
//指针和游标变量结合,用指针和下标遍历数组
for(p=a+N-1,j=N-1;j>=0;j--){
/**
* 这个地方刚开始一直没有看懂,后来明白了
* 当p=a+N-1时,就已经将该位置当作下标为0了
* 所以,其前一个元素就是a[-1]也就是4
*/
printf("p[-%d]\t= %d\t",j,p[-j]);
}
printf("\n");
return 0;
}
~~~
下面是我的程序运行的结果截图:
![这里写图片描述](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2016-05-24_5743c0754f499.jpg "")
使用指针比较整型数据的大小
最后更新于:2022-04-01 14:28:43
该C实例是一个比较简单的实例,但是在该实例中,重点介绍了C语言中比较常用的也是容易出错的指针变量,其中包括指针变量的赋值,指针变量的运算等等。该实例实现了通过使用指针变量来比较3个整形数据,使其从小到大排列,实现比较简单,下面附上我的代码:
~~~
#include <stdio.h>
/**
* 通过指针比较三个整数的大小
* @brief main
* @return
*/
/**
* 指针,即为变量的地址;指针变量,即数值为
* 指向变量地址的变量
* 指针变量的类型:
* 对指针变量的类型说明包括3个内容
* 1:指针类型说明,即定义变量为一个指针变量
* 2:指针变量名
* 3:变量值(指针)所指向的变量的数据类型
* 其一般形式为:
* 类型说明符 *变量名;
* 其中,*表示这是一个指针变量,变量名即为定义的指针变量名,
* 类型说明符表示本指针变量所指向的变量的数据类型
*
* 指针变量的赋值:
* C中提供了地址运算符"&"来表示变量的地址
* 要把整型变量a的地址赋予p可以有下面两种方式:
* (1)指针变量初始化方法
* int a;
* int *p = &a;
* (2)赋值语句的方法
* int a;
* int *p
* p = &a;
*
* 指针变量的元算:
* 1:指针运算法
* (1)取地址运算符&
* (2)取内容运算符*
* 2:指针变量的元算
* (1)赋值运算
* (2)加减运算符
*/
int main(void)
{
int x,y,z; //定义3个int类型的变量
int *xp = &x, /*定义指针变量xp,并赋值为x的地址,使其指向x*/
*yp = &y, /*定义指针变量yp,并赋值为y的地址,使yp指向y*/
*zp = &z; /*定义指针变量zp,并赋值为z的地址,是zp指向z*/
int t;
printf("Please input x,y,z:\n");
scanf("%d%d%d",xp,yp,zp); /* 通过变量的指针,为变量输入值 */
if(*xp > *yp){ /*通过指向变量的指针引用变量的值*/
t = *xp;
*xp = *yp;
*yp = t;
}
if(*xp > *zp){
t = *xp;
*xp = *zp;
*zp = t;
}
if(*yp > *zp){
t = *yp;
*yp = *zp;
*zp = t;
}
printf("x = %d,y = %d,z = %d\n",x,y,z);
return 0;
/**
* 与指针有关的类型:
* int i; //定义整型变量i
* int *p; //p为指向整型数据的指针变量
* int a[n]; //定义数组a,他有n个元素
* int *p[n]; //定义指针数组p,他有n个指向整型数据的指针元素组成
* int (*p)[n]; //p为指向n个元素的一维数组的指针变量
* int f(); //f为返回整型函数值的函数
* int *p(); //p为返回一个指针的函数,该指针指向整数型数据
* int (*p)(); //p为指向函数的指针,该函数返回一个整数值
* int **p; //p是一个指针变量,他指向一个指向整型数据的指针变量
*/
}
~~~
钢材切割问题
最后更新于:2022-04-01 14:28:40
已知钢材的总长,订单数和各订单需要的长度编制程序从订单中选择一组订单对钢材作切割加工, 使得钢材得到最佳应用,约定,每次切割损耗固定长度的钢材。
下面写一下我的思路,刚开始没有想明白应该怎么使用递归去做,但是,看了他们的代码之后,走了一遍,才明白,其实思路不太好想,但是实现起来还是比较容易的。
假设,我们有一段钢材,长度为12米,其中有3个订单,分别需要的长度为5,6,9米,每次切割总会有2米的损耗,求得其最佳订单组合。
现在我们想想一下我们正常的思路:
如果是只有一个订单的话,9米的订单是最合适的,加上2米的耗材,一共11米。
如果有两个订单的话,有组合5,6;5,9;6,9这三个组合,很明显,这三个组合都已经超过了12米的长度,因为如果是5,6的话,虽然说订单的和为11,但是有两次切割,还会有4米的耗材,加起来就是15米,已经远远超过钢材的长度了
由上面的可以知道,3个订单的组合那就更不行了。
那我们应该如何做到实现这个思路呢,我们有一个数组记录订单是否选中,请看下面这张图:
![这里写图片描述](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2016-05-24_5743c075353aa.jpg "")
5,6,9初始化的时候,全是未选中的状态,程序开始执行,先选中5,加上损耗的长度小于12,则继续选中6,这样加上损耗的长度大于12了,则设置6的状态为未选中;接着选中9,5加上9加上损耗的长度,很明显超过12了,那么设置9的状态为未选中;接着从5开始的遍历完成了,将5的状态设置为未选中;选中6,再从5开始选中,这样进行下去。。。。
当然,中间需要有两个变量记录最佳长度和最佳订单组合。
下面附上我的代码:
~~~
#include <stdio.h>
/**
* 已知钢材的总长,订单数和各订单需要的长度
* 编制程序从订单中选择一组订单对钢材作切割加工,
* 使得钢材得到最佳应用,约定,每次切割损耗
* 固定长度的钢材
*/
#define N 20
#define DELTA 2 //切割钢材损耗
/**最好的长度 **/
int bestlen;
/**最好长度的选定订单 **/
int bestsele[N];
/**选定订单,用于尝试选择 **/
int sele[N];
/**有n的订单 **/
int n;
/**订单需要的钢材的长度 **/
int orderlen[N];
/**钢材总长度 **/
int total;
void attempt();
int main(void)
{
int j;
//获取钢材的总长度
printf("Please enter the length of the steel:\n");
scanf("%d",&total);
//获取钢材的订单数
printf("Please enter the number of the orders:\n");
scanf("%d",&n);
//获取各个订单数需要的长度
printf("Please enter the length of every order:\n");
for(j = 0;j < n;j++)
scanf("%d",&orderlen[j]);
//初始化工作,使所有的订单都没有被选中
for(j = 0;j < n;j++)
bestsele[j] = sele[j] = 0;
//初始化最佳长度,设置为0
bestlen = 0;
//获取最佳长度
attempt();
printf("order:\n");
for(j = 0;j < n;j++){
if(bestsele[j])
printf("%d\t",orderlen[j]);
}
printf("\nlength:\n%d",bestlen);
return 0;
}
void attempt(){
int i,len;
//获取选中的订单的总长度(加上损耗)
for(len = i = 0;i < n;i++)
if(sele[i])
len += (orderlen[i]+DELTA);
if(len-DELTA <= total){ //注意,最后一个订单可能不需要损耗
if(bestlen < len){
bestlen = len;
for(i = 0;i < n;i++)
bestsele[i] = sele[i];
}
//每次尝试选择订单之后,需要将其还原未选中状态
for(i = 0;i < n;i++){
if(!sele[i]){
sele[i] = 1;
attempt();
sele[i] = 0;
}
}
}
}
~~~
C使用递归实现前N个元素的和
最后更新于:2022-04-01 14:28:38
递归函数,也就是不断的调用自身的函数,使用递归能够比较方便的解决一些比较难使用循环解决的问题。就在这个例子中,求一个数组a[]的前n项和,也就是求a[n-1]+a[n-2]+…+a[0],那么如果一个函数sum是用来求数组前n项和的,sum定义为sum(int a[],int n),则使用递归的方式就是
a[n-1]+sum(a,n-1)。
使用代码来表述可能更好一些:
~~~
#include <stdio.h>
int sum(int test[],int n);
/**
* @brief main 使用递归求一个数组的前n个元素的和
* 假设数组为a[];则求其前n的元素的和也就是求
* a[n-1]+a[n-2]+...a[0]
* @return
*/
int main(void)
{
int n;
printf("Please input the number of an array:\n");
scanf("%d",&n);
printf("Please enter the element of the array:\n");
int test[n];
int i;
for(i = 0;i < n;i++)
scanf("%d",&test[i]);
int count = sum(test,n);
printf("The sum of the array is : %d.\n",count);
return 0;
}
/**
* @brief sum 实现前n个元素的和
* @param test 要求和的数组
* @param n 所要求的前n个元素
* @return 返回前n个元素的和
*/
int sum(int test[],int n){
if(n <= 0)
return 0;
return test[n-1]+sum(test,n-1);
}
~~~
下面是我的程序的输出,这个程序比较简单。
![这里写图片描述](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2016-05-24_5743c0752130f.jpg "")
C判断一个正整数n的d进制数是否是回文数
最后更新于:2022-04-01 14:28:35
所有的有关于回文数的定义和如何判断一个n的d进制数是否是回文数的方法都在我的代码注释当中,直接上代码:
~~~
#include <stdio.h>
int circle(int n,int d);
/**
* @brief main 判断正整数n的d进制表示是否是回文数
* @return
*/
int main(void)
{
/**
* 回文数,就是顺着看和倒着看相同的书,例如n=232,十进制书表示为232,
* 顺着看和倒着看都是232,则表示n是回文数
* 判断n的d进制表示是否是回文数有两种办法
* 1:先把n转换成d进制表示,然后两个指针从前向后和从后向前
* 同时运算,比较两个char是否相等
*
* 2:先顺序译出n的d进制数,然后将各位数字按从低位到高位转换成一个
* 整数,看和n是否相等
*
* 这里我们使用第二种方式
*/
int n; //要被判断的正整数
//保存进制数
int ds[] = {2,10,16};
printf("Please enter the integer n:\n");
scanf("%d",&n);
int i = 0;
for(i = 0;i < sizeof(ds)/sizeof(ds[0]);i++){
int isCircle = circle(n,ds[i]);
if(isCircle == 0){
printf("%d => <%d>: is not circle!\n",n,ds[i]);
}else{
printf("%d => <%d>: is circle!\n",n,ds[i]);
}
}
return 0;
}
/**
* @brief circle 该函数用于判断一个正整数n的
* d进制数是否是回文数
* @param n 被判断的正整数n
* @param d 进制数
* @return 1-是回文数,0-不是回文数
*/
int circle(int n,int d){
int s = 0;
int m = n;
while(m){
s = s * d + m % d;
m /= d;
}
return s == n;
}
~~~
下面是我的程序的运行结果:
![这里写图片描述](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2016-05-24_5743c07505afa.jpg "")