秘书部第三次培训总结

秘书部第三次培训总结

指针复习

指针变量:一类通过地址访问指定内存存储单元的变量

1、三个符号& * +

& 用于取一般变量的地址, * 用于取指针变量的值

int a;		//定义一个一般变量a
int* p;		//定义一个指针变量p
p = &a;		//使用&取一般变量a的地址,并赋给指针变量p
printf("%d\n",*p);//使用*取指针变量的值,并输出

指针是一个地址,指针变量的自加和自减不是简单的在地址上的加1,而是获得下一个数据的地址,已知数组的名称就是该数组首元素的地址 ,那么数组名称加一就是第二个元素的地址。

	int *p, a[5], i = 0;
	p = a;						//p获取到数组a的首地址
	printf("please input array a:\n");
	for (i = 0; i < 5; i++)		//循环输入数组
	{
		scanf("%d", p);			//把键盘输入的整型传入p(一个地址)
		p++;					//让p指向下一个元素
	}
	p = a;						//重新让p获取到数组a的首地址
	printf("array a is:\n");
	for (i = 0; i < 5; i++)
	{
		printf("%5d", *p);		//输出地址p中的整型内容
		p++;					//让p指向下一个元素
	}
	printf("\n");

2、一个函数

C语言中函数一般是值传递,所以如果想把交换大小的代码用函数封装起来是没有用的

#include <stdio.h>
void swap(int i, int j);
int main() 
{
	int x = 1, y = 7;
	printf("在函数外,交换前的数据:%d\t%d\n", x, y);
	swap(x, y);
	printf("在函数外,交换后的数据:%d\t%d\n", x, y);
	return 0;
}
void swap(int i, int j)
{
	printf("在函数中,交换前的数据:%d\t%d\n", i, j);
	int temp = 0;
	temp = i;
	i = j;
	j = temp;
	printf("在函数中,交换后的数据:%d\t%d\n", i, j);
}

结果如图:
在这里插入图片描述
原理:函数swap在调用时会自动创建两个局部变量i,j并把参数x,y的值赋值给i,j,局部变量i,j只在函数体内有效,函数使用结束时会自动消除,在函数体的范围内i,j的值确实发生了交换,但是对于x和y,只是用到了他们的值,而没有对他们进行操作,自然也就不能改变x和y的值。

解决方法:地址传递
为了实现数值改变的封装函数,我们可以采用地址传递的方法(PS:注意这里不是引用传递
我们选择把数据的地址传入函数,通过地址修改地址中内容

#include <stdio.h>
void swap(int* i, int* j);	//函数参数为指针变量
int main() 
{
	int x = 1, y = 7;
	printf("在函数外,交换前的数据:%d\t%d\n", x, y);
	swap(&x, &y);			//使用取地址符号&获取x和y的地址,并传入函数
	printf("在函数外,交换后的数据:%d\t%d\n", x, y);
	return 0;
}
void swap(int* i, int* j)
{
	printf("在函数中,交换前的数据:%d\t%d\n", *i, *j);
	int temp = 0;
	temp = *i;				//通过取内容符号*获取地址中的内容,并进行修改
	*i = *j;
	*j = temp;
	printf("在函数中,交换后的数据:%d\t%d\n", *i, *j);
}

结果如图:
在这里插入图片描述
原理:函数开始调用时同样创建了局部指针变量i、j并且把传入参数的地址赋值给这两个指针变量,这样在函数体里就可以通过地址修改x和y的内容

结构体

“结构体”是一种构造类型。
构造类型:并不是C语言官方的,而是认为定义的只在一定范围内有效的数据类型。

1、结构体的概念

作为一种构造类型,结构体由若干“成员”组成,其中成员可以是基本数据类型或者是构造类型。
一般形式:
struct 结构体名
{
成员列表
};

结构体作为一种类型体现了“ 封装 ”的概念,将一种事物的几种属性封装到一起来表示这一种事物,比如说我们可以将“姓名”,“学号”,“成绩”几个属性封装到一起组成结构体学生作为数据类型学生。

struct Student
{
	char cName[20];		//字符串类型的学生姓名
	int iNo;			//整型的学生学号
	float fScore;		//浮点型的学生成绩
};

2、结构体的定义和初始化

声明一个结构体表示的是创建一中新的类型名,要用新的类型名载定义变量,这里我们介绍两种定义方式。
第一种:我们使用上面创建过的学生类来定义两个学生stu1和stu2。

struct Student stu1;
struct Student stu2;

第二种:在声明结构类型时,可以同时定义变量

struct Student
{
	char cName[20];
	int iNo;
	float fScore;
}stu3,stu4;

这样stu1、stu2、stu3、stu4就可以被使用了,他们四个都有各自的cName
、iNo、fScore属性。
与此同时:结构体数组也可以以相同的方式构造:

#include <stdio.h>
struct Student
{
	char cName[20];
	int iNo;
	float fScore;
}stu5[20];			//以第二种方式创建大小为20个的struct Student类型数组stu5
int main()
{
	struct Student stu6[20];//以第一种方法创建大小为20个的struct Student类型数组stu6
	return 0;
}

3、结构体的使用

定义结构体类型变量以后,就可以调用和操作结构体变量内部的成员,不能对结构体整体进行操作,结构体变量成员的一般形式为:结构体变量名.成员名
在结构体变量名后面加上成员运算符“ . ”和成员名字:

#include <stdio.h>
#include <string.h>
struct Student
{
	char cName[20];
	int iNo;
	float fScore;
}
int main()
{
	struct Student stu1;
	strcpy(stu1.cName,"FirStu");
	stu1.fScore = 100;
	scanf("%d",&stu1.iNo);
	stu1.iNo++;
	printf("%s  %d  %f",stu1.cName,stu1.iNo,stu1.fScore);
	return 0;
}

4、结构体指针

字面理解,即指向结构体变量起始位置的指针,既然指针指向结构体变量的地址,因此可以使用结构体指针来访问结构体中的成员。
定义结构体的一般形式:结构体类型 *指针名;

#include <stdio.h>
struct Student
{
	char cName[20];
	int iNo;
	float fScore;
}
int main()
{
	struct Student * stu1;
	return 0;
}

结构体指针有两种方式可以对其中的成员进行引用:
第一种:使用 * 对结构体指针取内容,并使用成员运算符 .
第二种:直接通过箭头 -> 调用,结构体指针名->成员名

struct Student * stu1;
(*stu1).iNo = 11;
stu1->fScore = 120;

结构体指针的举例说明:

#include <stdio.h>
#include <string.h>
struct Student
{
	char cName[20];
	int iNo;
	float fScore;
};
int main()
{
	struct Student * pStu;
	struct Student stu;
	pStu = &stu;

	strcpy(pStu->cName, "FirStu");
	pStu->iNo = 2018;
	pStu->fScore = 120;

	(*pStu).fScore++;

	printf("-----the student's information ----\n");
	printf("Name:%s\n", stu.cName);
	printf("No:%d\n", stu.iNo);
	printf("Score:%f\n", stu.fScore);
	return 0;
}

运行结果:
在这里插入图片描述

链表

链表,一种有关线性表的链式存储户结构,一种常见的数据结构

1、链表的概念

链表由一系列结点(链表中每一个元素称为结点)组成,结点可以在运行时动态生成。每个结点包括两个部分:一个是存储数据元素的数据域,另一个是存储下一个结点地址的指针域。
在这里插入图片描述
C语言中,我们为了把数据和指针封装到一个整体,采用结构体,每一个节点是一个结构体,一个结构体中包括数据和指向下一个结构体的指针。一般来说,这里的一条数据链上的结构体类型都是一致的。
下面我们使用C语言创建一个这样的结构体

struct Student
{
	char cName[20];
	int iNo;
	struct Student * pNext;
}

这里的pNext就是一个指针,它可以指向一个struct Student类型。

2、动态链表的生成

使用函数动态生成一个链表,并返回链表头。
这个函数利用键盘输入链表节点数据,并且设定当输入的学号iNo为0时结束链表的生成。

/*
==========================
功能:创建n个节点的链表
返回:指向链表表头的指针
==========================
*/
struct Student *Create()
{
	struct Student *pHead = NULL;		//头节点
	struct Student *p1 = NULL;			//p1保存创建的新节点的地址
	struct Student *p2 = NULL;			//p2保存原链表最后一个节点的地址

	iCount = 0;							//创建前链表的节点总数为0:空链表
	p1 = (struct Student *) malloc(sizeof(struct Student));	//开辟一个新节点
	p2 = p1;							//如果节点开辟成功,则p2先把它的指针保存下来以备后用

	if (p1 == NULL)						//节点开辟不成功
	{
		printf("\nCann't create it, try it again in a moment!\n");
		return NULL;
	}
	else								//节点开辟成功
	{
		printf("Please input %d node -- iNo,fScore: ", iCount + 1);
		scanf("%d %f", &(p1->iNo), &(p1->fScore));	//录入数据
	}
	while (p1->iNo != 0)					//只要学号不为0,就继续录入下一个节点
	{
		iCount += 1;					//节点总数增加1个
		if (iCount == 1)					//如果节点总数是1,则pHead指向刚创建的节点p1
		{
			pHead = p1;
			p2->pNext = NULL;			//此时的p2就是p1,也就是p1->next指向NULL。
		}
		else
		{
			p2->pNext = p1;				//指向上次下面刚刚开辟的新节点
		}

		p2 = p1;						//把p1的地址给p2保留,然后p1产生新的节点

		p1 = (struct Student *) malloc(sizeof(struct Student));
		printf("Please input %d node -- iNo,fScore: ", iCount + 1);
		scanf("%d %f", &(p1->iNo), &(p1->fScore));
	}
	p2->pNext = NULL;					//此句就是根据单向链表的最后一个节点要指向NULL

	free(p1);							//p1->iNo为0的时候跳出了while循环,并且释放p1
	p1 = NULL;							//特别不要忘记把释放的变量清空置为NULL,否则就变成"野指针",即地址不确定的指针
	return pHead;						//返回创建链表的头指针 
}

3、链表输出

使用函数将以head为链表头的链表输出出来

/*
===========================
 功能:输出节点
 返回: void
===========================
*/
void Print(struct Student *head)
{
	struct Student *p;
	printf("\nNow , These %d records are:\n", iCount);
	p = head;
	if (head != NULL)					//只要不是空链表,就输出链表中所有节点
	{
		printf("head is %o\n", head);	//输出头指针指向的地址
		while (p != NULL)
		{
			/*
			输出相应的值:当前节点地址、各字段值、当前节点的下一节点地址。
			这样输出便于读者形象看到一个单向链表在计算机中的存储结构,和我们
			设计的图示是一模一样的。
			*/
			printf("%o   %d   %5.1f   %o\n", p, p->iNo, p->fScore, p->pNext);
			p = p->pNext;
		}
	}
}

4、链表中指定节点的删除

删除指定链表在指定位置的节点

/*
==========================
 功能:删除指定节点
  (此例中是删除指定学号的节点)
 返回:指向链表表头的指针
==========================
*/
struct Student *Del(struct Student *head, int no)
{
	struct Student *p1;		//p1保存当前需要检查的节点的地址
	struct Student *p2;		//p2保存当前检查过的节点的地址
	if (head == NULL)		//是空链表
	{
		printf("\nList is null!\n");
		return head;
	}

	//定位要删除的节点
	p1 = head;
	while (p1->iNo != no && p1->pNext != NULL)//p1指向的节点不是所要查找的,并且它不是最后一个节点,就继续往下找
	{
		p2 = p1;			//保存当前节点的地址
		p1 = p1->pNext;		//后移一个节点
	}

	if (p1->iNo == no)		//找到了
	{
		if (p1 == head)		//如果要删除的节点是第一个节点
		{
			head = p1->pNext;//头指针指向第一个节点的后一个节点,也就是第二个节点。这样第一个节点就不在链表中,即删除
		}
		else				//如果是其它节点,则让原来指向当前节点的指针,指向它的下一个节点,完成删除
		{
			p2->pNext = p1->pNext;
		}

		free(p1);			//释放当前节点
		p1 = NULL;
		printf("\ndelete %ld success!\n", no);
		iCount -= 1;		//节点总数减1个
	}
	else					//没有找到
	{
		printf("\n%ld not been found!\n", no);
	}

	return head;
}

5、链表中在指定位置插入节点

调用函数,在链表的指定位置插入节点

/*
==========================
 功能:插入指定节点的后面
  (此例中是指定学号的节点)
 返回:指向链表表头的指针
==========================
*/
struct Student *Insert(struct Student *head, int no, struct Student *node)
{
	if (head == NULL)
	{
		head = node;
		node->pNext = NULL;
		iCount += 1;
		return head;
	}

	struct Student *p1 = head;	//p1保存当前需要检查的节点的地址
	while (p1->iNo != no && p1->pNext != NULL)//p1指向的节点不是所要查找的,并且它不是最后一个节点,继续往下找
	{
		p1 = p1->pNext;			//后移一个节点
	}

	if (p1->iNo == no)			//找到了
	{
		node->pNext = p1->pNext;//显然node的下一节点是原p1的next
		p1->pNext = node;		//插入后,原p1的下一节点就是要插入的node
		iCount += 1;			//节点总数增加1个
	}
	else
	{
		printf("\n%ld not been found!\n", no);
	}
	return head;
}

文件

“文件”是指一组相关数据的有序集合。这个数据集有一个名称,叫做文件名。
文件指针是一个西乡文件有关信息的指针,这些信息包括文件名,状态和当前位置。使用文件时需要在内存中为其分配空间,用来存放文件的基本信息。

1、文件的打开、关闭与操作安全

定义一个文件指针:FILE * file;
打开文件函数:fopen(文件路径,使用文件方式)
关闭文件函数:fclose(文件名)
C语言中对于文件的使用方式要细分为“读”,“写”,“追加”
“读”:指的是从文件头开始读取数据;
“写”:指的是从文件头开始写入数据,文件种原来的数据会被覆盖;
“追加”:指的是从文件尾部写入数据,文件中原来的数据会被保留;
而且由于C语言中打开的文件分为“文本文件”和“二进制文件”,所以不同的文件类型对应的同一种文件打开方式的名称不同。
在这里插入图片描述
文件打开的代码举例:

FILE * file;
file = fopen("E://my//123.txt","w");	//使用只写方式打开E盘下的my文件夹下的123.txt文件
//......文件相关操作
fclose(file);
file = fopen("E://my//123.txt","a");	//使用只写方式打开E盘下的my文件夹下的123.txt文件
//......文件相关操作
close(file);

文件打开和关闭的安全问题
对于fopen函数,如果打开成功,返回文件指针,如果打开失败,返回NULL空针;
对于fclose函数,如果关闭成功,返回整型0,如果关闭失败,返回EOF;
可以通过这两个函数返回值得特性来确保文件打开与关闭的安全性,代码示例:

#include <stdio.h>
int main()
{
	FILE * file;
	if((file = fopen("E://my//123.txt","w")) == NULL)
	{
		printf("文件打开失败!\n");
		exit(0);		//安全退出函数
	}
	//......文件打开已成功......文件操作
	if(fclose(file) == EOF)
	{
		printf("文件关闭失败");
		exit(0);		//安全退出函数
	}
	return 0;
}

2、文件的fprintf写入和fscanf读取

C语言中,printf是把数据输入到缓冲区,scanf为把缓冲区数据读出,
则,fprintf是把数据输入到文件流,fscanf把文件流中的数据读出。
函数使用:
fprintf(文件指针,格式字符串,输出列表),fscanf(文件指针,格式字符串,输出列表)
代码示例:
fprintf的使用

#include <stdio.h>
int main()
{
	FILE * file;
	char ch;
	if((file = fopen("E://my//123.txt","w")) == NULL)
	{
		printf("文件打开失败!\n");
		exit(0);		//安全退出函数
	}
	//===========fprintf==========
	while (scanf("%c", &ch) != EOF) 	//从键盘输入字符
	{
		if (ch == '#') { break; }		//如果输入字符#跳出while循环
		fprintf(file, "%c", ch);		//将输入的字符输出到file文件指针所指向的文件
	}
	if(fclose(file) == EOF)
	{
		printf("文件关闭失败");
		exit(0);		//安全退出函数
	}
	return 0;
}

fscanf的使用

#include <stdio.h>
int main()
{
	FILE * file;
	char ch;
	if((file = fopen("E://my//123.txt","w")) == NULL)
	{
		printf("文件打开失败!\n");
		exit(0);		//安全退出函数
	}
	//===========fscanf==========
	while (fscanf(file, "%c", &ch) != EOF) //从file文件依次读出字符到ch,指导文件结束
	{
		printf("%c", ch);
	}
	if(fclose(file) == EOF)
	{
		printf("文件关闭失败");
		exit(0);		//安全退出函数
	}
	return 0;
}

对于fscanf函数,只有读取到文件末尾的时候,会返回EOF,可以通着这个返回值得特性判断文件读取是否结束

3、文件的fputc写入和fgetc读取

fputc函数的一般形式: fputc(ch,file),此时文件应该是以“读”或者“只读”的方式打开
可以把一个字符写到文件指针file所指的文件中,其中ch是要输出的字符,如果输出成功返回输出的字符,如果失败,返回EOF
fgetc函数的一般形式:ch = fgetc(file),此时文件应该是以“写”或者“只写”的方式打开
从文件指针file所指的文件中读取一个字符赋给ch,此函数当遇到文件结束符时返回EOF
fputc

#include <stdio.h>
int main()
{
	FILE * file;
	char ch;
	if((file = fopen("E://my//123.txt","w")) == NULL)
	{
		printf("文件打开失败!\n");
		exit(0);		//安全退出函数
	}
	//===========fputc==========
	while (scanf("%c", &ch) != EOF) 	//从键盘输入字符
	{
		if (ch == '#') { break; }		//如果输入字符#跳出while循环
		fputc(ch,file);		//将输入的字符输出到file文件指针所指向的文件
	}
	if(fclose(file) == EOF)
	{
		printf("文件关闭失败");
		exit(0);		//安全退出函数
	}
	return 0;
}

fgetc

#include <stdio.h>
int main()
{
	FILE * file;
	char ch;
	if((file = fopen("E://my//123.txt","w")) == NULL)
	{
		printf("文件打开失败!\n");
		exit(0);		//安全退出函数
	}
	//===========fgets==========
	while ((ch=fgetc(file)) != EOF) //从file文件依次读出字符到ch,指导文件结束
	{
		printf("%c", ch);
	}
	if(fclose(file) == EOF)
	{
		printf("文件关闭失败");
		exit(0);		//安全退出函数
	}
	return 0;
}

4、文件的fputs写入和fgets读取

fputs函数和fputc函数相类似,区别在于,fputc每次只能项文件中写入一个字符,二fputs每次项文件中写入一个字符串
fputs函数的一般形式:fputs(字符串,文件指针)
fputs

#include <stdio.h>
int main()
{
	FILE * file;
	char ch[10] = {'a','b','c','d'};
	if((file = fopen("E://my//123.txt","w")) == NULL)
	{
		printf("文件打开失败!\n");
		exit(0);		//安全退出函数
	}
	//===========fputs==========
	fputs(ch,file);
	if(fclose(file) == EOF)
	{
		printf("文件关闭失败");
		exit(0);		//安全退出函数
	}
	return 0;
}

fgets

#include <stdio.h>
int main()
{
	FILE * file;
	char ch[10];
	if((file = fopen("E://my//123.txt","w")) == NULL)
	{
		printf("文件打开失败!\n");
		exit(0);		//安全退出函数
	}
	//===========fgets==========
	fgets(file,ch);
	if(fclose(file) == EOF)
	{
		printf("文件关闭失败");
		exit(0);		//安全退出函数
	}
	return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值