C语言复习_四

十一 共用体(联合体)

  1. 联合union是一个能在同一个存储空间存储同类型数据的类型;
  2. 联合体所占的内存长度等于其最长成员的长度倍数,也有叫做共用体;
  3. 同一内存段可以用来存放几种不同类型的成员,但每一瞬时只有一种起作用
  4. 共用体变量中起作用的成员是最后一次存放的成员,在存入一个新的成员后原有的成员的值会被覆盖;
  5. 共用体变量的地址和它的各成员的地址都是同一地址。

11.1 共用体的定义和使用

#include<stdio.h>
//	定义一个共用体
	union test
	{
		int a;
		short b;
		float c;
		double d; //8个字节
		char e;
	};
//	共用体是最后一次赋值的数据是有效的
int main()
{
//	创建共用体变量
	union test var;
	var.a=100;
	printf("%d\n",var.a);
	var.c=3.14;
	printf("%f\n",var.c);

	return 0;
}

十二 链表(数据结构)

通过结构体构成链表,单向链表的建立,结点数据的输出、删除与插入

  1. 链表是一种常用的数据结构,它通过指针将一些列数据结点,连接成一个数据链。相对于数组,链表具有更好的动态性(非顺序存储链式存储。
  2. 数据域用来存储数据,指针域用于建立与下一个结点的联系。
  3. 建立链表时无需预先知道数据总量的,可以随机的分配空间,可以高效的在链表中的任意位置实时插入或删除数据。
  4. 链表的开销,主要是访问顺序性和组织链的空间损失。

数组和链表的区别

数组:一次性分配一块连续的存储区域。

优点:随机访问元素效率高

缺点:1) 需要分配一块连续的存储区域(很大区域,有可能分配失败)

      2) 删除和插入某个元素效率低

链表:无需一次性分配一块连续的存储区域,只需分配n块节点存储区域,通过指针建立关系。

优点:1) 不需要一块连续的存储区域

  2) 删除和插入某个元素效率高

数组:一次性分配一块连续的存储区域。

优点:随机访问元素效率高

缺点:1) 需要分配一块连续的存储区域(很大区域,有可能分配失败)

      2) 删除和插入某个元素效率低

链表:无需一次性分配一块连续的存储区域,只需分配n块节点存储区域,通过指针建立关系。

优点:1) 不需要一块连续的存储区域

  2) 删除和插入某个元素效率高

数组:一次性分配一块连续的存储区域。

优点:随机访问元素效率高

缺点:1) 需要分配一块连续的存储区域(很大区域,有可能分配失败)

      2) 删除和插入某个元素效率低

链表:无需一次性分配一块连续的存储区域,只需分配n块节点存储区域,通过指针建立关系。

优点:1) 不需要一块连续的存储区域

  2) 删除和插入某个元素效率高

缺点:随机访问元素效率低

 十三 位运算

13.1 位运算符的含义和使用

可以使用C对变量中的个别位进行操作。您可能对人们想这样做的原因感到奇怪。这种能力有时确实是必须的,或者至少是有用的。C提供位的逻辑运算符和移位运算符。在以下例子中,我们将使用二进制计数法写出值,以便您可以了解对位发生的操作。在一个实际程序中,您可以使用一般的形式的整数变量或常量。例如不适用00011001的形式,而写为25或者031或者0x19.在我们的例子中,我们将使用8位数字,从左到右,每位的编号是7到0

十进制转成二进制 除二取余法

二进制转成十进制  权值法:将各个二进制位从末尾开始乘以二的n次幂

十进制

八进制

十六进制

13.2 位逻辑运算符

4个位运算符用于整型数据,包括char.将这些位运算符成为位运算的原因是它们对每位进行操作,而不影响左右两侧的位。请不要将这些运算符与常规的逻辑运算符(&& 、||和!)相混淆,常规的位的逻辑运算符对整个值进行操作

按位取反~

一元运算符~将每个1变为0,将每个0变为1,如下面的例子:

~(10011010)

01100101

在位运算中根据数据类型进行运算符的补位操作在数据前补0

计算机会采用二进制补码存储数据

负数的原码转补码

负数的源码转换为补码:1、先转换为反码(符号位不变,数值位按位取反)2、在反码的基础上末位加一

负数的补码转换为原码:符号位不变,数值位按位取反,末位加一。
例如:

十进制数:123

转二进制:01111011(原码)

补码:01111011

反码:10000100(~123)

反码11111011(-123的反码)

补码:11111100(-123的补码)

  正数的反码和补码都与原码相同。

  负数的反码为对该数的原码除符号位外各位取反。

  负数的补码为对该数的原码除符号位外各位取反,然后在最后一位加1

#include<stdio.h>
int main()
{
	char a=20;
//	00010100
//	11101011 //按位取反
//	10010100//反码
	//补码:10010101 -21
//~按位取反
	printf("%d\n",~a);
	return 0;
}
位与(AND): &

二进制运算符&通过对两个操作数逐位进行比较产生一个新值。对于每个位,只有两个操作数的对应位都是1时结果才为1。

#include <stdio.h>
int main()
{
	//	int a=10;
	//	int b=20;
	int a=15;
	int b=52;
//	将a转为二进制得  0000 1111
	//将52转为二进制得 0011 0100
	//	相与得到:00000100
//	&位于运算的操作
	//将10转为二进制 00001010
	//将20转为二进制 00010100
	//相与得: 00000000
	printf("%d\n",a&b);
}
位或(OR): |

二进制运算符|通过对两个操作数逐位进行比较产生一个新值。对于每个位,如果其中任意操作数中对应的位为1,那么结果位就为1.

(10010011)

  | (00111101)

  = (10111111)

int main()
{
	int a=10;
	int b=20;
//将10转为二进制 0000 1010
	//将20转为二进制 0001 0100
//进行或运算 0001 1110
printf("%d\n",a|b);
	return 0;
}

位异或: ^

相同为0 不同为1

二进制运算符^对两个操作数逐位进行比较。对于每个位,如果操作数中的对应位有一个是1(但不是都是1),那么结果是1.如果都是0或者都是1,则结果位0.

int main()
{
	int a=10;
	int b=20;
//将10转为二进制 0000 1010
//将20转为二进制 0001 0100
//	异或:		 0001 1110  30
	printf("%d\n",a^b);
}
左移 <<

左移运算符<<将其左侧操作数的值的每位向左移动,移动的位数由其右侧操作数指定。空出来的位用0填充,并且丢弃移出左侧操作数末端的位。在下面例子中,每位向左移动两个位置。

#include<stdio.h>
int main()
{
	int a=10;
	//0000 1010
//	<<0001 0100
	printf("%d\n",a<<1);
}
右移 >>

右移运算符>>将其左侧的操作数的值每位向右移动,移动的位数由其右侧的操作数指定。丢弃移出左侧操作数有段的位。对于unsigned类型,使用0填充左端空出的位。对于有符号类型,结果依赖于机器。空出的位可能用0填充,或者使用符号(最左端)位的副本填充。

#include<stdio.h>
int main06()
{
	int a=10;
	//0000 1010
//	<<0001 0100
//	位移运算符每次移动相当于乘以2的n次幂
	printf("%d\n",a<<1);
}
int main()
{
	int a=10;
	//0000 1010
	//0000 0101
	printf("%d\n",a>>1);
	return 0;
}
11.2.1 打开位

已知:10011010:

将位2打开

flag |  10011010

(10011010)

|(00000100)

=(10011110)

将所有位打开。

flag | ~flag

(10011010)

|(01100101)

=(11111111)

 交换两个数不需要临时变量

#include<stdio.h>
int main()
{
	int a=10;
	int b=20;
//	交换 a和b的值
//	int temp;
//	temp=a;
//	a=b;
//	b=temp;
	//	使用异或运算符
	//操作步骤
	//0000 1010
	//0001 0100
	//	异或
//	 0001 1110 a=30
//	操作步骤2
//	0001 1110
//	0001 0100
//	异或  0000 1010 //10
//	操作步骤3
//	0001 1110
//	0000 1010
//	0001 0100 //20
	a=a^b;
	b=a^b;
	a=a^b;
	printf("%d\n",a);
	printf("%d\n",b);
}

移位运算符

11.2.5移位运算符

移位运算符能够提供快捷、高效(依赖于硬件)对2的幂的乘法和除法。

number << n

number乘以2的n次幂

number >> n

如果number非负,则用number除以2的n次幂

十四 文件操作

文件类型指针(FILE类型指针)

在C语言中用一个指针变量指向一个文件,这个指针称为文件指针。 

typedef struct

{

short           level; //缓冲区"满"或者"空"的程度

unsigned        flags; //文件状态标志

char            fd; //文件描述符

unsigned char   hold; //如无缓冲区不读取字符

short           bsize; //缓冲区的大小

unsigned char   *buffer;//数据缓冲区的位置

unsigned        ar;  //指针,当前的指向

unsigned        istemp; //临时文件,指示器

short           token; //用于有效性的检查

}FILE;

FILE是系统使用typedef定义出来的有关文件信息的一种结构体类型结构中含有文件名、文件状态和文件当前位置等信息

C语言中有三个特殊的文件指针由系统默认打开,用户无需定义即可直接使用:

  1. stdin: 标准输入,默认为当前终端(键盘),我们使用的scanf、getchar函数默认从此终端获得数据。
  2. stdout:标准输出,默认为当前终端(屏幕),我们使用的printf、puts函数默认输出信息到此终端。

stderr:标准出错,默认为当前终端(屏幕),我们使用的perror函数默认输出信息到此终端

文件的打开与关闭

任何文件使用之前必须打开:

#include <stdio.h>

FILE * fopen(const char * filename, const char * mode);

功能:打开文件

参数:

filename:需要打开的文件名,根据需要加上路径

mode:打开文件的模式设置

返回值:

成功:文件指针

失败:NULL

第一个参数的几种形式:

FILE *fp_passwd = NULL;

//相对路径:

//打开当前目录passdw文件:源文件(源程序)所在目录

FILE *fp_passwd = fopen("passwd.txt", "r");

//打开当前目录(test)下passwd.txt文件

fp_passwd = fopen(". / test / passwd.txt", "r");

//打开当前目录上一级目录(相对当前目录)passwd.txt文件

fp_passwd = fopen(".. / passwd.txt", "r");

//绝对路径:

//打开C盘test目录下一个叫passwd.txt文件

fp_passwd = fopen("c:/test/passwd.txt","r");

第二个参数的几种形式(打开文件的方式):

打开模式

含义

r或rb

以只读方式打开一个文本文件(不创建文件,若文件不存在则报错)

w或wb

以写方式打开文件(如果文件存在则清空文件,文件不存在则创建一个文件)

a或ab

以追加方式打开文件,在末尾添加内容,若文件不存在则创建文件

r+或rb+

以可读、可写的方式打开文件(不创建新文件)

w+或wb+

以可读、可写的方式打开文件(如果文件存在则清空文件,文件不存在则创建一个文件)

a+或ab+

以添加方式打开文件,打开文件并在末尾更改文件,若文件不存在则创建文件

 

文件的关闭

任何文件在使用后应该关闭:

  1. 打开的文件会占用内存资源,如果总是打开不关闭,会消耗很多内存
  2. 一个进程同时打开的文件数是有限制的,超过最大同时打开文件数,再次调用fopen打开文件会失败
  3. 如果没有明确的调用fclose关闭打开的文件,那么程序在退出的时候,操作系统会统一关闭。
#include <stdio.h>
int fclose(FILE * stream);
功能:关闭先前fopen()打开的文件。此动作让缓冲区的数据写入文件中,并释放系统所提供的文件资源。
参数:
	stream:文件指针
返回值:
	成功:0
	失败:-1

 

#include<stdio.h>
#include <stdlib.h>
int main()
{
	FILE *fp;
//	fopen(文件路径,打开方式) 打开文件
//	打开方式 r 只读方式打开 w 写方式打开 a以追加方式打开
//	在文件操作中 所有路径都需要写[/]文件的名称都需要添加扩展名
	fp=fopen("D:/a.txt","r");
//	对打开的文件进行判断 nULL表示空指针
	if(fp ==NULL){
		printf("打开文件失败");
		return -1;
	}
	printf("文件打开成功%p\n",fp);
	//关闭文件
	fclose(fp);
	return 0;
}

文件的读写

 按照字符读写文件fgetc、fputc

 按照字符读写文件fgetc、fputc
1)写文件

#include <stdio.h>

int fputc(int ch, FILE * stream);

功能:将ch转换为unsigned char后写入stream指定的文件中

参数:

ch:需要写入文件的字符

stream:文件指针

返回值:

成功:成功写入文件的字符

失败:返回-1

char buf[] = "this is a test for fputc";

int i = 0;

int n = strlen(buf);

for (i = 0; i < n; i++)

{

//往文件fp写入字符buf[i]

int ch = fputc(buf[i], fp);

printf("ch = %c\n", ch);

}

#include <stdio.h>

int fgetc(FILE * stream);

功能:从stream指定的文件中读取一个字符

参数:

stream:文件指针

返回值:

成功:返回读取到的字符

失败:-1

char ch;

#if 0

while ((ch = fgetc(fp)) != EOF)

{

printf("%c", ch);

}

printf("\n");

#endif

while (!feof(fp)) //文件没有结束,则执行循环

{

ch = fgetc(fp);

printf("%c", ch);

}

printf("\n");

 按照行读写文件fgets、fputs 

写文件

#include <stdio.h>

int fputs(const char * str, FILE * stream);

功能:将str所指定的字符串写入到stream指定的文件中,字符串结束符 '\0'  不写入文件。

参数:

str:字符串

stream:文件指针

返回值:6

成功:0

失败:-1

char *buf[] = { "123456\n", "bbbbbbbbbb\n", "ccccccccccc\n" };
int i = 0;
int n = 3;
for (i = 0; i < n; i++)
{
	int len = fputs(buf[i], fp);
	printf("len = %d\n", len);
}

文件结尾

在C语言中,EOF表示文件结束符(end of file)。在while循环中以EOF作为文件结束标志,这种以EOF作为文件结束标志的文件,必须是文本文件。在文本文件中,数据都是以字符的ASCII代码值的形式存放。我们知道,ASCII代码值的范围是0~127,不可能出现-1,因此可以用EOF作为文件结束标志。

当把数据以二进制形式存放到文件中时,就会有-1值的出现,因此不能采用EOF作为二进制文件的结束标志。为解决这一个问题,ANSI C提供一个feof函数,用来判断文件是否结束。feof函数既可用以判断二进制文件又可用以判断文本文件。

#include<stdio.h>
int main03()
{
	FILE* fp;
	char ch;
	fp=fopen("D:/a.txt","r");
	if(fp==NULL)
	{
		printf("打开文件失败\n");
		return -1;

	}
	while((ch =fgetc(fp))!=EOF){
	printf("%c",ch);
	}
	fclose(fp);
	return 0;
}

int main()
{
	char ch='A';
	FILE* fp;
	fp=fopen("D:/b.txt","w");
	if(fp ==NULL)
		return -1;
	
	fputc(ch,fp);
	fclose(fp);
}

按照格式化文件fprintf、fscanf

1)写文件

#include <stdio.h>

int fprintf(FILE * stream, const char * format, ...);

功能:根据参数format字符串来转换并格式化数据,然后将结果输出到stream指定的文件中,指定出现字符串结束符 '\0'  为止。

参数:

stream:已经打开的文件

format:字符串格式,用法和printf()一样

返回值:

成功:实际写入文件的字符个数

失败:-1

fprintf(fp, "%d %d %d\n", 1, 2, 3);

2)读文件

#include <stdio.h>

int fscanf(FILE * stream, const char * format, ...);

功能:从stream指定的文件读取字符串,并根据参数format字符串来转换并格式化数据。

参数:

stream:已经打开的文件

format:字符串格式,用法和scanf()一样

返回值:

成功:参数数目,成功转换的值的个数

失败: - 1

按照块读写文件fread、fwrite

1)写文件

#include <stdio.h>

size_t fwrite(const void *ptr, size_t size, size_t nmemb, FILE *stream);

功能:以数据块的方式给文件写入内容

参数:

ptr:准备写入文件数据的地址

size: size_t 为 unsigned int类型,此参数指定写入文件内容的块数据大小

nmemb:写入文件的块数,写入文件数据总大小为:size * nmemb

stream:已经打开的文件指针

返回值:

成功:实际成功写入文件数据的块数目,此值和 nmemb 相等

失败:0

读文件

#include <stdio.h>

size_t fread(void *ptr, size_t size, size_t nmemb, FILE *stream);

功能:以数据块的方式从文件中读取内容

参数:

ptr:存放读取出来数据的内存空间

size: size_t 为 unsigned int类型,此参数指定读取文件内容的块数据大小

nmemb:读取文件的块数,读取文件数据总大小为:size * nmemb

stream:已经打开的文件指针

返回值:

成功:实际成功读取到内容的块数,如果此值比nmemb小,但大于0,说明读到文件的结尾。

失败:0

 

文件的定位

#include <stdio.h>

int fseek(FILE *stream, long offset, int whence);

功能:移动文件流(文件光标)的读写位置。

参数:

stream:已经打开的文件指针

offset:根据whence来移动的位移数(偏移量),可以是正数,也可以负数,如果正数,则相对于whence往右移动,如果是负数,则相对于whence往左移动。如果向前移动的字节数超过了文件开头则出错返回,如果向后移动的字节数超过了文件末尾,再次写入时将增大文件尺寸。

whence:其取值如下:

SEEK_SET:从文件开头移动offset个字节

SEEK_CUR:从当前位置移动offset个字节

SEEK_END:从文件末尾移动offset个字节

返回值:

成功:0

失败:-1

#include <stdio.h>

long ftell(FILE *stream);

功能:获取文件流(文件光标)的读写位置。

参数:

stream:已经打开的文件指针

返回值:

成功:当前文件流(文件光标)的读写位置

失败:-1

#include <stdio.h>

void rewind(FILE *stream);

功能:把文件流(文件光标)的读写位置移动到文件开头。

参数:

stream:已经打开的文件指针

返回值:

无返回值

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值