4.指针---动态分配内存---文件操作

指针

  • 作用:代码块与代码块之间的数据传递
  • 指针:一个变量的地址称为该变量的指针
  • 指针变量:专门用来放另一个变量地址的变量

注意

  • 指针变量的类型由指向的那个变量的类型决定
  • 指针变量里面存储的是指向的那个变量的地址
  • 定义指针变量的时候必须赋初值,如果暂时没有初值,用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
4.指针---动态分配内存---文件操作_第1张图片
文件变化
  • 字符串读写函数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值

你可能感兴趣的:(4.指针---动态分配内存---文件操作)