c语言自学笔记

本文详细介绍了C语言中字符串转其他类型字符的方法,如atoi、atof和atol。讨论了变量的作用域,包括局部变量和全局变量,以及它们的生命周期。深入讲解了内存的四个区域:代码段、数据段、栈和堆。此外,还涵盖了堆空间的分配和释放,以及命名冲突、静态变量和静态函数的使用。最后,阐述了fprintf、fgets、fwrite和fread等文件操作函数的用法,并探讨了文件读写指针和随机位置读取的相关概念。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

字符串转其他型字符

变量定义:

        atoi:字符串 转 整数

int atoi(const char *str1);

        atof:字符串 转 浮点数

double num2 = atof(str2);

        atol:字符串 转 长整数

long num3 = atol(str3);

使用这类函数进行转换,要求,原串必须是可转换的字符串。

int main(void) {
	char str1[] = "10";
	int num1 = atoi(str1);
	printf("num1=%d\n",num1);

	char str2[] = "0.123f";
	double num2 = atof(str2);
	printf("num2=%.2lf\n",num2);

	char str3[] = "123L";
	long num3 = atol(str3);
	printf("num3=%ld\n",num3);

	system("pause");
	return EXIT_SUCCESS;
}

局部变量:

        定义在函数内部的变量。

        作用域:从定义位置开始,到包裹该变量的第一个右大括号结束。


void test1(void) {
	if (1) {
		int a = 10;
	}
	printf("a=%d\n",a);    //此时a无法打印,因局部变量原因不承认IF中的a在本段结束
}

if语句,for循环,while循环等中的变量定义仅在循环括号中有定义

全局变量:

        概念:定义在函数外部的变量

        作用域:从定义位置开始,到本文件内部。其他文件如果想使用,可以通过声明将作用域导出。

extern int a;	//显示声明,将其他文件的定义值导出到此文件

void test1(void) {
	printf("a=%d\n",a);

}

int main(void) {
	printf("a=%d\n", a);
	
	system("pause");
	return EXIT_SUCCESS;
}

//同时其他文件定义a的值

static全局变量:

       定义语法: 在变量定义之前添加static关键字。        static int a=10;

       作用域:被限制在本文件内部,不允许通过声明导出到其他文件。//即加上静态就无法从别的文件中导出定义。

static局部变量:

        定义语法:在局部变量定义之前添加static关键字。

        特性:静态局部变量只定义一次,在全局位置。        //通常用来做计数器。

        作用域:从定义位置开始,到包裹该变量的第一个右大括号结束。

全局函数:

        定义语法:函数原型+函数体

static函数:

        定义语法:static+函数原型+函数体

static函数 只能在 本文件内部使用。其他文件即使声明也无效。

生命周期:

局部变量:从变量定义开始到函数调用完成。----函数内部

全局变量:程序启动开始,程序终止结束。 ----程序执行期间

static局部变量:程序启动开始,程序终止结束  -----程序执行期间

static全局变量:程序启动开始,程序终止结束  -----程序执行期间

全局函数:

内存4区模型:

        代码段:text段,程序源代码(二进制形式)

数据段:只读数据段.rodata段,初始化数据段.data ,未初始化数据段.bss

stack:栈。在其中开辟 栈帧。 Windows  1m-----10m     LINUX:8m-----16M

heap:堆。给用户自定义数据提供空间。约1.3G+

命名冲突就近原则:

        例1:

int m = 100;
int main(void) {
	int m = 30;
	printf("m=%d\n",m);

}

输出:

m=30 

例2:

int main(void) {
	int m = 30;

	for (size_t m = 0; m < 10; m++) {
		printf("m=%d\n",m);
	}
	printf("m=%d\n",m);

	system("pause");
	return EXIT_SUCCESS;
}

输出:

m=0
m=1
m=2
m=3
m=4
m=5
m=6
m=7
m=8
m=9
m=30

堆空间的申请和使用:

 开辟释放heap空间:

        void *malloc(siuze_t size);  申请size大小的空间

                        返回实际申请到的内存空间首地址。【我们通常拿来当数组用】

        void free(void*ptr);释放申请的空间

int main(void) {
	int* p = (int*)malloc(sizeof(int) * 10);
	if (p == NULL) {
		printf("malloc error\n");
		return -1;
	}
	//申请malloc空间
	for (size_t i = 0; i <10; i++)
	{
		p[i] = i + 10;
	}
	//写数据到malloc空间
	for (size_t i = 0; i < 10; i++)
	{
		printf("%d ",*(p+i));
	}
	//读出malloc空间中的数据
	free(p);		
	//释放申请的内存
}

使用heap堆空间:

        空间时连续。当成数组使用。

        free后的空间,不会立即失效,通常将free后的地址重置为NULL。

        free地址必须是malloc申请地址。否则出错

        如果malloc之后的地址一定会变化,那么使用临时变量tmp保存。

二级指针malloc空间:

        

int main(void) {
	int** p = malloc(sizeof(int *)*10);
	//int **p ==>int *p[10];==>[int *,int *,int *]
	for (size_t i = 0; i < 10; i++)
	{
		p[i]=malloc(sizeof(int) * 5);
	}
	for (size_t i = 0; i <10; i++)
	{
		for (size_t j = 0; j<5; j++)
		{
			p[i][j] = i + j;
		}
	}
	//使用空间 -- 写
	for (size_t i = 0; i < 10; i++)
	{
		for (size_t j = 0; j < 5; j++)
		{
			printf("%d",*(*(p+i)+j));		//p[i][j]==*(p+i)[j]==*(*(p+i)+j)
		}
	}
	//使用空间 -- 写

	for (size_t i = 0; i < 10; i++)
	{
		free(p[i]);
		p[i] = NULL;
	}
	//释放空间时, 先释放内层空间。
	free(p);
	p = NULL;
	//释放外层空间
	system("pause");
	return EXIT_SUCCESS;
}

申请外层指针:char **p=malloc(sizeof(char)*5);

申请内层指针:

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

        {

        p[i]=(char*)malloc(sizeof(char)*10);

        }

使用:

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

{

strcpy(p[i],"helloheap");

}

释放内层:

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

        {

       free(p[i]);

        }

释放外层:

        free(p);

fprintf()函数:

        printf---sprintf---fprintf: 都是变参函数:参数形参中,有“...”,最后一个固参通常是格式描述串(包含格式匹配符),函数的参数个数、类型、顺序由固参决定。

fprintf()和printf()一样工作. 
printf是打印输出到屏幕,fprintf是打印输出到文件。 
fprintf()的返回值是输出的字符数,发生错误时返回一个负值. 

printf("hello");

printf("%s","hello");

printf("ret=%d+%d\n",10,5);

printf("%d=%d%c%d\n","10+5",10,'+',5);        ---》屏幕

char buf[1024];

sprintf(buf,"%d%c%d\n",10+5,10,'+',5);        -->buf中

FILE *fp=fopen();初始化

fprintf(fp,"%d%c%d\n",10+5,10,'+',5);        --》fp对应的文件中

void write_file() {
	FILE* fp = fopen("abc.c","w");
	if (!fp) {
		perror("fopen error");
		return -1;
	}//fp ==NULL
	printf("%d%c%d=%d\n",10,'*',7,10*7);

	fclose(fp);

	system("pause");
	return EXIT_SUCCESS;
}

int main(void) {
	write_file();


	system("pause");
	return EXIT_SUCCESS;
}

perror函数简介
perror(s) 用来将上一个函数发生错误的原因输出到标准设备(stderr)。参数 s 所指的字符串会先打印出,后面再加上错误原因字符串。此错误原因依照全局变量errno的值来决定要输出的字符串。在库函数中有个errno变量,每个errno值对应着以字符串表示的错误类型。当你调用"某些"函数出错时,该函数已经重新设置了errno的值。perror函数只是将你输入的一些信息和errno所对应的错误一起输出。  

scanf---sscanf---fscanf

        scanf("%d",&m);                键盘---》m

        char str[ ]=="98";

        sscanf(str,"%d",&m);              str---》m

        FILE *fp=fopen("r");

fscanf(fp,"%d",&m);        fp指向的文件中 --》m

        例1:

void write_file() {
	FILE* fp = fopen("abc.c","w");
	if (!fp) {
		perror("fopen error");
		return -1;
	}//fp ==NULL
	printf("%d%c%d=%d\n",10,'*',7,10*7);

	fclose(fp);

	system("pause");
	return EXIT_SUCCESS;
}

void read_file() {
	int a, b, c;
	char ch;
	FILE* fp = fopen("abc.c","r");
	if (!fp) //fp=NULL
	{
		perror("fopen error");
		return -1;
	}
	fscanf(fp, "%d%c%d=%d\n", &a, &ch, &b, &c);

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

	fclose(fp);
}

例2: 

void write_file() {
	FILE* fp = fopen("abc.c","w");
	if (!fp) {
		perror("fopen error");
		return -1;
	}//fp ==NULL
	fprintf(fp, "%d\n", 10);
	fprintf(fp, "%d\n", 8);
	fprintf(fp, "%d\n", 6);

	fclose(fp);

	system("pause");
	return EXIT_SUCCESS;
}
void read_file() {
	int a;
	FILE* fp = fopen("abc.c","r");
	if (!fp) //fp=NULL
	{
		perror("fopen error");
		return -1;
	}
	fscanf(fp, "%d\n", &a);
	printf("%d\n",a);

	fscanf(fp, "%d\n", &a);
	printf("%d\n", a);

	fscanf(fp, "%d\n", &a);
	printf("%d\n", a);

	fscanf(fp, "%d\n", &a);
	printf("%d\n", a);

	fclose(fp);
}

输出第四次时与之前第三次一样,但实际这属于边界溢出。

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

   1.边界溢出。存储读取数的数据空间。在使用之前清空。

    2.fscanf函数,每次在调用时都会判断下一次调用是否匹配参数2,如果不匹配提前结束文件读操作。(feof(fp))

fgets:

C库函数char *fgets(char *str, int n, FILE *stream) 从指定的流stream读取一行,并把它存储在 str 所指向的字符串字符串字符串内。当读取 (n-1) 个字符时,或者读取到换行符时,或者到达文件末尾时,它会停止,具体视情况而定。

void read_file3() {
	char buf[1024];
	FILE* fp = fopen("abc.c", "r");
	if (!fp)//fp=NULL
	{
		perror("fopen error");
		return -1;
	}
	while (1) {
		fgets(buf, 1024, fp);
		printf("%d\n",a);
		if (feof(fp))
			break;
	}
	fclose(fp);
}

文件排序练习

void write_rand() {
	FILE* fp = fopen("text123.txt", "w");
	if (!fp) {
		perror("fopen error");
		return -1;
	}

	srand(time(NULL));	//随机数种子
	for (size_t i = 0; i < 10; i++){
		rand() % 100;	//0 - 99
	}
	fprintf(fp,"%d\n",rand()%100);
}

void BubbleSort(int* src, int len) {
	for (int i = 0; i < len - 1; i++) {
		for (int j = 0; j < len - 1 - i; j++) {
			if (src[j] > src[j + 1]) {
				int tmp = src[j];
				src[j] = src[j + 1];
				src[j + 1] = tmp;
			}
		}
	}
}
//排序


void read_rand() {
	int arr[10], i = 0;		//定义循环因子给初值
	int tmp;

	FILE* fp = fopen("text123.txt","r");
	if (!fp) {
		perror("fopen error");
		return -1;
	}
	while (1) {
		fscanf(fp, "%d\n",&arr[i]);
		i++;
		if (feof(fp)) {
			break;
		}
	}
	for (size_t i = 0; i < 10; i++){
		printf("%d\n",arr[i]);
	}
	BubbleSort(arr, sizeof(arr) / sizeof(arr[0]));	//排序

	fclose(fp);

	fp = fopen("text123.txt", "w");	//清空原未排文件
	if (!fp) {
		perror("fopen error");
		return -1;
	}
	for (size_t i = 0; i < 10; i++) {
		printf("%d\n", arr[i]);
	}//排好序的文件
	fclose(fp);
}


int main() {
	read_rand();

	system("pause");
	return EXIT_SUCCESS;
}

fwrite函数:

fgets--fputc

fgets--fputs

fprintf-fscanf

默认处理文本文件。用来处理二进制文件

fwrite()函数:写出数据到文件中。

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

参数1:待写出数据的地址

参数2:待写出数据的大小

参数3:写出的个数

---参数2  x  参数3=写出数据的总大小

返回值:

成功:一直是参数3的值

失败:0

typedef struct student {
	int age;
	char name[10];
	int num;
}stu_t;

int main(void) {
	stu_t stu[4] = {
		18,"lzx",10,
		19,"wzh",20,
		20,"wxf",30,
		21,"cl",40,
	};
	FILE* fp = fopen("text123.txt", "w");
	if (!fp) {
		perror("fopen error");
		return -1;
	}
	int ret =fwrite(&stu[0], sizeof(stu_t), 1,fp);
	if (ret == 0) {
		perror("fwrite error");
		return -1;
	}
	printf("ret==%d\n",ret);

	fclose(fp);
	system("pause");
	return EXIT_SUCCESS;
}

输出:

ret ==1

 fread函数:

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

参数1:读取到的数据存储的位置

参数2:一次读取的字节数

参数3:读取的次数                ----参数2 x  参数3  =读取数据的总大小

参数4:文件

返回值:

成功:参数3

失败:0

 0:读取失败 --feof(fp)--到达文件结尾

typedef struct student {
	int age;
	char name[10];
	int num;
}stu_t;

void write_struct() {
	stu_t stu[4] = {
	18,"lzx",10,
	19,"wzh",20,
	20,"wxf",30,
	21,"cl",40,
	};
	FILE* fp = fopen("text123.txt", "w");
	if (!fp) {
		perror("fopen error");
		return -1;
	}
	int ret = fwrite(&stu[0], sizeof(stu_t), 1, fp);
	if (ret == 0) {
		perror("fwrite error");
		return -1;
	}
	printf("ret==%d\n", ret);

	fclose(fp);
}

void read_struct() {
	FILE* fp = fopen("text123.txt", "r");
	if (!fp) {
		perror("fopen error");
		return -1;
	}
	stu_t buf[1024];    //stu_t *buf=malloc(sizeof(stu_t)*1024);

	int ret=fread(&buf, sizeof(stu_t), 1, fp);
	printf("ret=%d\n",ret);

	printf("age=%d,name=%s,num=%d\n",buf.age,buf.name,buf.num);

	fclose(fp);
}

int main(void) {
	read_struct();

	system("pause");
	return EXIT_SUCCESS;
}

大文件拷贝实现:

已知一个任意类型的文件,对该文件复制,产生一个相同的新文件。

1.打开两个文件,一个“r”,另一个“w”

2.从r中fread,fwrite到w文件中。

void myfile_cp() {
	FILE* rfp = fopen("C:\\XXXX\\XXX.TXT","r");
	FILE* wfp = fopen("C:\\XXXX\\XXX.TXT", "w");

	char buf[128] = { 0 };    //缓冲区
	int ret = 0;
	while (1) {
		ret = fread(bug, 1, sizeof(buf), rfp);
		if (ret == 0) {
			break;
		}
		fwrite(buf,1,ret,wfp);
	}
	fclose(wfp);
	fclose(rfp);
}

int main(void) {
	myfile_cp();

	printf("---finish\n");

	system("pause");
	return EXIT_SUCCESS;
}

随机位置 读:

文件读写指针

fseek():

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

        参数1:文件

        参数2:偏移量(矢量:+向后, -向前)

        参数3:SEEK_SET:文件开头位置

                      SEEK_CUR:当前位置

                      SEEK_END:文件结尾位置

ftell():

        获取文件读写指针的位置

        long ftell(FILE *stream);

        返回:从文件当前读写位置到起始位置的偏移量。

        借助ftell+fseek(seek_end):来获取文件大小。

rewind():

        回卷文件读写指针,将读写指针移到起始位置。

        void rewind(FILE*stream):

typedef struct student {
	int age;
	char name[10];
	int num;
}stu_t;

int main(void) {
	stu_t stu[4] = {
	18,"lzx",10,
	19,"wzh",20,
	20,"wxf",30,
	21,"cl",40,
	};

	stu_t s1;

	FILE* fp = fopen("text1.txt", "wb+");
	if (!fp) {
		perror("fopen error");
		return -1;
	}
	int ret=fwrite(&stu[0],1,sizeof(stu),fp);	//以二进制形式写入
	fseek(fp, sizeof(stu_t), SEEK_SET);	//从文件起始位置开始,向后偏移一个stu结构体
	ret=fread(&s1, 1, sizeof(s1), fp);

	rewind(fp);	//将文件读写指针回卷到起始位置。

	printf("ret=%d\n",ret);
	printf("age=%d,name=%s,num=%d\n",s1.age,s1.name,s1.num);

	int len=ftell(fp);	//获取文件当前偏移位置到文件起始位置的偏移量。


	fseek(fp, 0, SEEK_END);//获取文件大小
	len = ftell(fp);

	printf("文件大小为:%d\n", len);
	fclose(fp);
	system("pause");
	return EXIT_SUCCESS;
}

LINUX和windows的文件区别:

        1.对于二进制文件操作,Windows使用“b”,Linux下二进制和文本没区别。

        2.windows下,回车\r ,换行\n。LINUX下\r\n会转换成\n

        3.对文件指针,先写后读。windows和linux效果一致。

                                先读后写。LINUX无需修改,windows下需要在写操作之前使用fseek(fp,0,SEEK_CUR);来获取文件读写指针,使之生效。

int main(int argc,char *argv[]) {
	FILE* fp = fopen("text1.txt", "r+");

	char buf[6] = { 0 };
	char* ptr = fgets(buf, 6, fp);

	printf("buf=%s,ptr=%s\n,ptr,buf");

	int ret = fputs("AAAAA",fp);

	printf("ret=%d\n",ret);

	fclose(fp);
	return 0;
	system("pause");
}

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值