高级指针
指针即内存地址
内存地址: 4G虛拟内存 编号0-4G 0x0000 0000 - 0xffffffff
指针变量: 保存内存地址的变量
*内存地址 取值
&变量 取址
定义指针变量:
类型 *p; 类型:p存储的地址上存储的数据类型
int *p; int* 是指针的类型 int是指p存储的地址,那片地址上的数据类型
指针算术运算:
p+1; p++;
指针+1,加了单位长度的内存地址
NULL 悬空指针
野指针
万能指针 void*
指针与数组:
int arr[5];
int *p = arr; arr == &*arr == &*(arr+0) == &arr[0]
一维数组名其实就是数组首元素的地址
数组名和普通的指针的区别在于 数组名不能作为左值
p[1] *(p+1) arr[1] *(arr+1)
&arr 数组的地址
&arr 和 arr 值相同 但类型不同
arr+1 偏移了一个数组元素的长度
&arr+1 偏移了整个数组的长度
int (*parr)[5] = &arr;
数组指针: 本质是一个指针 该指针指向一个数组
T (*pname)[n];
数组指针pname指向一个一维数组 数组长度为n 数组中存储的元素类型为T
指针数组: 本质是一个数组 数组中的元素为指针
T * arr[n]; 数组中所有元素的类型为 T*
二维数组与指针:
int arr[3][4] = {};
int (*parr)[4] = arr == &*arr == &*(arr+0) == &arr[0]
arr --> func(int (*parr)[4]) func(int arr[][4])
parr == arr == &arr[0]
*parr == *arr == *&arr[0] == arr[0] == &arr[0][0]
**parr == **arr == *arr[0] == arr[0][0]
int *p = arr[0] == &*arr[0] == &*(arr[0]+0) == &arr[0][0]
*(*(arr+1)+2) === arr[1][2]
int (*pa)[3][4] = &arr;
函数与指针:
函数名即内存地址
函数指针: 本质是指针 该指针指向一个函数
T (*pname)(ARGS,...);
函数指针pname 指向一个函数 该函数返回值类型为T,参数为ARGS
int * func(int *p){}
int * (*pf)(int *); //pf是一个函数指针变量
pf = func;
int a = 0;
pf(&a); //调用函数
typedef T (*PF)(ARGS...); //给函数指针类型取别名 PF
PF pf;
PF arr[5];//函数指针数组
void (*pf[5])(void); //函数指针数组
#include <signal.h>
typedef void (*sighandler_t)(int);
sighandler_t signal(int signum, sighandler_t handler);
指针函数: 本质是函数 函数返回一个指针类型
定义一个指针函数指针数组变量:
T* (*parr[n])(...)
T* (*parr[n])(...);
是数组 是指针数组 是指针函数指针数组
看定义识标识符是什么?
首先拿到标识符 parr 从标识符往后结合
如果是 [ 是数组
如果是 ( 是函数
如果是 ) 则往前结合
如果是 * 是指针
然后把上面结合的内容看作一个整体重复上面的动作
int compAsc(int x,int y){
return x-y;
}
int compDesc(int x,int y){
return y-x;
}
void sort(int arr[],size_t n){
int i,j;
for(i=1;i<n;i++){
int key = arr[i];
//for(j=i-1;j>=0&&arr[j]>key;–j){
//for(j=i-1;j>=0&&arr[j]-key>0;–j){
//for(j=i-1;j>=0&&compAsc(arr[j],key)>0;–j){
//for(j=i-1;j>=0&&arr[j]<key;–j){
//for(j=i-1;j>=0&&key-arr[j]>0;–j){
//for(j=i-1;j>=0&&compAsc(key,arr[j])>0;–j){
for(j=i-1;j>=0&&compDesc(arr[j],key)>0;–j){
arr[j+1] = arr[j];
}
arr[j+1] = key;
}
}
文件操作
数据的持久化
打开文件进行读写操作 关闭文件
程序启动时把数据从文件中加载(load)进来
程序退出时把数据从内存中保存(dump)到文件中
FILE *fopen(const char *path, const char *mode);
失败返回NULL 成功返回FILE* 用于读写文件时传递的参数
path: 文件路径 "a.txt" 默认是当前目录
mode: 模式
r Open text file for reading. The stream is positioned
at the beginning of the file.
r+ Open for reading and writing. The stream is
positioned at the beginning of the file.
如果文件不存在,则失败
w Truncate file to zero length or create text
file for writing. The stream is positioned at
the beginning of the file.
w+ Open for reading and writing. The file is created
if it does not exist, otherwise it is truncated.
The stream is positioned at the beginning of the file.
如果文件存在,则清空
rw+ reading and writing 保留内容
a Open for appending (writing at end of file).
The file is created if it does not exist. The
stream is positioned at the end of the file.
a+ Open for reading and appending (writing at end
of file). The file is created if it does not
exist. The initial file position for reading
is at the beginning of the file, but output is
always appended to the end of the file.
b: 以二进制的形式读写
以文本形式读写
二进制模式和文本模式在linux下无区别
在windows有区别: 在换行时有区别 python
size_t fread(void *ptr, size_t size, size_t nmemb, FILE *stream);
size: 期望每次读取数据的字节数
nmemb: 期望读多少次
size_t fwrite(const void *ptr, size_t size, size_t nmemb,FILE *stream);
返回成功写入的个数 与nmemb有关
返回0表示写入失败
数据以什么样的方式写入到文件,那么请以什么样的方式读取出来
int fscanf(FILE *stream, const char *format, ...);//从文件中格式输入
int fprintf(FILE *stream, const char *format, ...);//格式化输出到文件
int fgetc(FILE *stream);
char *fgets(char *s, int size, FILE *stream);
int getc(FILE *stream);
int fputc(int c, FILE *stream);
int fputs(const char *s, FILE *stream);
int putc(int c, FILE *stream);
int fseek(FILE *stream, long offset, int whence);//设置文件读写位置
offset: 偏移的字节数 可正可负 正表示向关 负表示向文件末尾偏移
whence: 参考位置
SEEK_SET 文件开始位置
SEEK_CUR 当前位置
SEEK_END 文件末尾位置
long ftell(FILE *stream); 获得文件读写位置 距离文件开始位置的字节数
void rewind(FILE *stream); 把读写位置调整到文件开始位置
int fclose(FILE *fp);
练习:
实现cp命令的功能
文件复制
a.out srcpath destpath
写一个函数,计算一个文件的大小!
long filesize(const char *path){
if(path==NULL){
return -1;
}
FILE *fp = fopen(path,"r");
if(fp == NULL){
return -2;
}
fseek(fp,0,SEEK_END);//放到文件末尾
long size = ftell(fp);
fclose(fp);
return size;
}
fseek(fp,10,SEEK_END);//不会占内存大小 形成的文件空洞 ftell可以得到偏移值
读写文件时会有一个文件指针位置,即文件读写的位置
这个位置很重要!!!