指针
- 作用:代码块与代码块之间的数据传递
- 指针:一个变量的地址称为该变量的指针
- 指针变量:专门用来放另一个变量地址的变量
注意
- 指针变量的类型由指向的那个变量的类型决定
- 指针变量里面存储的是指向的那个变量的地址
- 定义指针变量的时候必须赋初值,如果暂时没有初值,用NULL
- 指针变量本身占据(永远只占)8个字节的内存空间
动态分配内存
解决数组一开始就明确元素个数的问题
需要引入stdlib.h这个标准库头文件,可以使用两个函数,malloc:分配内存,free:释放内存
-
步骤:
1.调用malloc函数来申请内存空间2. 检测malloc函数的返回值,以得知操作系统是否成功为我们的程序分配了这块内存空间
3. 一旦使用完这块内存,不再需要时,必须用free函数来释放占用的内存,不然可能会造成内存泄漏
malloc函数:申请内存
void* malloc(内存空间的大小(字节));
//返回void *指针,可以表示任意指针类型的指针
//void *指针与其它类型指针之间可以通过强制转化来相互转换
//void *x = (int *)x;
int main(int argc, const char * argv[]) {
int *memoryAllocated = NULL;
memoryAllocated = malloc(sizeof(int));
if (memoryAllocated == NULL) {//如果分配内存失败
exit(0);//立刻停止程序
}
//分配成功,可以继续接下来的操作
return 0;
}
//一般来说内存不会分配失败,但是也有极端情况:1.堆内存不够了;2.申请内存大的离谱
//所以每次使用malloc函数都需要给指针做测试
- free函数:释放内存
int main(int argc, const char * argv[]) {
int *memoryAllocated = NULL;
memoryAllocated = malloc(sizeof(int));
if (memoryAllocated == NULL) {//如果分配内存失败
exit(0);//立刻停止程序
}
//此处添加使用这块内存的代码
free(memoryAllocated);//我们不再需要这块内存,释放它
return 0;
}
- 小例子
//自动
#include
#include
int main(int argc, const char * argv[]) {
int *memoryAllocated = NULL;
printf("你几岁了?\n");
scanf("%d",memoryAllocated);
printf("你已经%d岁了\n",*memoryAllocated);
return 0;
}
//手动
#include
#include
int main(int argc, const char * argv[]) {
int *memoryAllocated = NULL;
memoryAllocated = malloc(sizeof(int));//分配内存
if (memoryAllocated == NULL) {//检测是否分配成功
exit(0);//不成功,结束程序
}
//使用这块内存
printf("你几岁了?\n");
scanf("%d",memoryAllocated);
printf("你已经%d岁了\n",*memoryAllocated);
free(memoryAllocated);//释放这块内存
return 0;
}
//运行结果
你几岁了?
6
你已经6岁了
Program ended with exit code: 0
- 动态分配优势
动态分配最常被用来创建在运行时才知道大小的变量,例如动态数组
优点1:可以在运行时才确定申请的内存空间大小
优点2:不多不少刚刚好,不会浪费内存
#include
#include
int main(int argc, const char * argv[]) {
int numFriends = 0;
int *ageFriends = NULL;//这个指针用来只是朋友年龄的数组
printf("请问有多少个小朋友?\n"); //询问有多少个小朋友
scanf("%d",&numFriends);
if (numFriends > 0) {//数据要合理
ageFriends = malloc(numFriends*sizeof(int));
if (ageFriends == NULL) {//检测是否分配成功
exit(0);//分配不成功,退出程序
}
//诸葛询问小朋友年龄
for (int i = 0; i < numFriends; i++) {
printf("第%d位朋友的年龄是:",i+1);
scanf("%d",&ageFriends[i]);
}
//逐个输出小朋友年龄
printf("你的朋友年龄如下:\n");
for (int i = 0; i < numFriends; i++) {
printf("%d岁\n",ageFriends[i]);
}
free(ageFriends);//释放内存
}
return 0;
}
//运行结果
请问有多少个小朋友?
5
第1位朋友的年龄是:8
第2位朋友的年龄是:5
第3位朋友的年龄是:6
第4位朋友的年龄是:7
第5位朋友的年龄是:4
你的朋友年龄如下:
8岁
5岁
6岁
7岁
4岁
Program ended with exit code: 0
- 总结
1.不同类型的变量在内存中所占的大小不尽相同
2.借助sizeof这个关键字(也是运算符)可以知道一个类型所占的字节数
3.动态分配就是在内存中手动地预留一块空间给一个变量或者数组
4.动态分配的常用函数是malloc(当然还有calloc,realloc,可以查阅使用方法,和malloc是类似的),但是在不需要这块内存之后,千万不要忘了使用free函数来释放。而且,malloc和free要一一对应,不能一个malloc对应两个free,会出错;或者两个malloc对应一个free,会内存泄露!
5.动态分配使得我们可以创建动态数组,就是它的大小在运行时才能确定
文件操作
- 文件指针
FILE *指针变量标识符
作用:通过该指针即可找到存放某个文件信息的结构变量,然后按结构变量提供的信息找到该文件,实施对文件的操作
- 文件的打开和关闭
1.文件的打开
格式:文件指针名 = fopen(文件名,使用文件方式);
文件指针名:必须是被说明为FILE类型的指针变量
文件名:文件的类型,是字符串常量或者字符串数组
使用文件方式:对文件的操作要求
文件操作符 | 作用 |
---|---|
r(read) | 读 |
w(write) | 写 |
a(append) | 追加 |
t(text) | 文本文件,可省略不写 |
b(banary) | 二进制文件 |
+(+号) | 读和写 |
注意:
凡是用“r”打开一个文件时,该文件必须已经存在,且只能从该文件读出
用“w”打开文件只能向该文件写入。若不存在,则建立新文件;若存在,则删除old文件,重新建立新的文件
向一个已存在的文件追加新的信息,只能用“a”的方式
在打开一个文件时,如果出错,则fopen返回一个空指针值NULL
把一个文本文件读入内存时,要将ASCLL码转换成二进制码,而把文件以文本方式写入磁盘是,也要将二进制码转换成ASCLL码
标准输入文件(键盘),标准输出文件(显示器),标准出错输出(出错信息)是由系统打开的,可直接使用
2.文件的关闭
格式: fclose(文件指针);
作用: 避免文件的数据丢失,正常完成关闭文件时,fclose函数返回值为0,如返回非零值则表示有错误发生
特别注意:写完一定要fclose不然不会把缓存中的数据写到磁盘中,导致下面的操作出问题
文件的读写
字符读写函数 : fgetc 和 fputc
字符串读写函数 : fgets 和 fputs
数据块读写函数 : fread 和 fwrite
格式化读写函数 : fscanf 和 fprintf字符读写函数fgetc 和 fputc
字符读写函数是以‘字符(字节)’为单位的读写函数。每次可从文件读出或向文件写入一个字符
读字符函数fgetc
格式: 字符变量 = fgetc(文件指针)
作用: 从指定的文件中读一个字符
注意 :
fgetc函数调用中,读取的文件必须是以读或读写方式打开的
读取字符的结果可以不向字符变量赋值
在文件内部有一个位置指针,第一次总是第一个字节。多次读取时,注意位置指针的位置
fegetc返回一个读到的字符,结尾或出错返回EOF(-1的一个宏,end of file)
写字符函数fputc
格式: fputc(字符量,文件指针)
作用: 把一个字符写入指定的文件中
注意 :
被写入的文件可以用写、读写、追加方式打开,写入字符从文件首开始
每写入一个字符,文件内部指针位置向后移动一个字节
fputc返回一个写入的字符,写入失败返回EOF。可以此来判断写入是否成功
//练习:写入a-z的字符并读取
#include
int main(int argc, const char * argv[]) {
FILE *fp = fopen("/Users/xulei/Desktop/stuInfo.txt", "w");
if (fp == NULL) {
printf("error");
}
for (int i = 'a'; i <= 'z'; i++) {
printf("%-3c",fputc(i, fp));
}
printf("\n");
fclose(fp);
FILE *fpr = fopen("/Users/xulei/Desktop/stuInfo.txt", "r");
if (fpr == NULL) {
printf("error");
}
char ch;
while ((ch = fgetc(fp)) != EOF) {
printf("%-3c",ch);
}
printf("\n");
fclose(fpr);
return 0;
}
//运行结果
a b c d e f g h i j k l m n o p q r s t u v w x y z
a b c d e f g h i j k l m n o p q r s t u v w x y z
Program ended with exit code: 0
- 字符串读写函数fgets 和 fputs
读字符串函数fgets
格式: fgets(字符数组名,n,文件指针)
作用: 从指定的文件中读一个字符串到字符数组中
注意: n是一个整数。表示从文件中读出的字符串不超过n-1个字符,在读入的最后一个字符后加上串结束标志’\0‘
写字符串函数fputs
格式: fputs(字符串/字符数组名,文件指针)
作用: 从指定的文件中写入一个字符串到字符数组中
- 数据块读写函数fread 和 fwrite
读数据块数据的格式: fread(buffer,size,count,fp);
写数据块数据的格式: fwrite(buffer,size,count,fp);
其中
buffer -- 是一个指针,在fread函数中,它表示存放输入数据的首地址。在fwrite函数中,它表示存放输出数据的首地址。
size -- 表示数据库的字节数
count -- 表示要读写的数据库块数
fp -- 表示文件指针
实例:
fread(fa,4,5,fp); --> 意义: 是从fp所指的文件中,每次读4个字节(一个实数)送入实数组fa中,连续5次,即读5个实数到fa中
- 格式化读写函数fscanf 和 fprintf
格式化读 : fscanf(文件指针,格式字符串,输入表列);
格式化写 : fprintf(文件指针,格式字符串,输出表列);
- 文件定位
rewind(文件指针);
功能: 把文件内部的位置指针移到文件首。
fseek(文件指针,位移量,起始点);
功能: 移动文件内部的位置指针到指定的位置。
解释:
“文件指针”: 指向被移动的文件
“位移量” : 表示移动的字节数,要求位移量是long型数据。要求加后缀"L"
“起始点”: 表示从何处开始计算位移量,规定: 文件首(0),当前位置(1),文件尾(2);---> 数字为相应的表示
- 文件检测函数
文件结束检测函数feof函数
格式: feof(文件指针);
功能: 判断文件是否处于文件结束的位置,结束(1),未完(0)
读写文件出错检测函数
格式: ferror(文件指针);
功能: 检查文件在各种输入输出函数进行读写时是否出错,未出错(0),有错(1)
文件出错标志和文件结束标志置0函数
格式: clearerr(文件指针);
功能: 用于清除出错标志和文件结束标志。使他们为0值