C语言教程指针笔记整理(三)
https://www.bilibili.com/video/BV1cx4y1d7Ut?spm_id_from=333.788.videopod.episodes&vd_source=e8984989cddeb3ef7b7e9fd89098dbe8&p=107
本篇为贺宏宏老师C语言教程指针部分笔记整理
//8-23 字符串作为参数传递
//字符串和普通数组的区别:字符串可以通过’\0’来判断结尾,不需要传递长度
//不使用库函数,实现字符串赋值
//des:目标地址。n1:目的数组长度,省略
//src:源字符串地址。n2:源字符串的长度,省略
void Mystrcpy(char* des,const char *src)//源字符串不允许修改,所以要把定义改成const char *str
{
int i;
for(int i = 0; i < sizeof(src)/sizeof(src[0]); i++)
{
if(src[i] != '\0')
des[i] = src[i];
else
des[i] = '\0';
}
//按照老师这样是错的,也不知道为什么,可能是他用的VS,我用的VScode
//int i;
//for(int i = 0;src[i] != '\0'; i++)
// des[i] = src[i];
//des[i] = '\0';
}
int main()
{
char str1[] = "abcde";
char str2[10];
//调用Mystrcpy,实现把str1复制到str2中
//c语言中有strcpy函数,以后可以直接用
Mystrcpy(str2,str1);
printf("str2 = %s\n",str2);
//char str3[] = "abc";
const char str3 = 'abc'
char str4[] = "cba";
printf("str4 = %s,str3 = %s\n",str4,str3);
strcpy(str4,str3);//源字符串不允许修改,所以要把定义改成const char str3
printf("str4 = %s,str3 = %s",str4,str3);
return 0;
}
//8-24 函数指针的介绍
int Max(int a, int b)
{
return a >= b ? a : b;//注意这里先问号,后冒号。是不是啊?是的话这样,否则就那样
}
int Min(int a, int b)
{
return a <= b ? a : b;
}
int Avg(int a, int b)
{
return (a+b)/2;
}
void main()
{
int(*pfun)(int,int);//pfun一定是指针,指向什么?指向一个(),()是什么?是函数,所以pfun指向一个函数,函数的参数是int,int,返回值是int
pfun = Max;//等价于pfun = Max;
//pfun = Min;//等价于pfun = Min;
//pfun = Avg;//等价于pfun = Avg;
//注意这里没有加&取地址符也没有报错 //为什么呢?
//因为,标准规定,函数名,也表示函数的入口地址,即Max=&Max;就像数组名也表示数组的地址一样
printf("%d\n",pfun(10,20));//调用的是Max函数
}
//测试
void main()
{
//int(*pfun) = Max();//错误
//int(*pfun)= Max(int,int);//错误
//int(*pfun)= Max(int a,int b);//错误
int(*pfun)(int,int) = Max;//正确,说明指向某一函数的指针类型必须得和函数输入输出变量的类型保持一致
printf("%d\n",pfun(10,20));
}
//8-25 qsort中函数指针的引用
int Max(int a, int b)
{
return a >= b ? a : b;//注意这里先问号,后冒号。是不是啊?是的话这样,否则就那样
}
int Min(int a, int b)
{
return a <= b ? a : b;
}
int Avg(int a, int b)
{
return (a+b)/2;
}
//qsort:对任意的数据进行排序(升序)最不好处理的是如何比较两个数据的大小(例如学生可能是分数,也可能是身高,也可能是体重。。。。)
//所以,需要提供对数据比较的依据,即需要知道数据的类型
//比较函数返回值:
//if第一个>第二个,返回一个大于0的数字,
//if第一个>第二个,返回0,
//if第一个<第二个,返回一个小于0的数字。
int Com_int(const void* vp1,const void* vp2)
{
return *(int *) vp1 - *(int *)vp2;//还原本质
}
int Com_double(const void* vp1,const void* vp2)
{
//return *(double *) vp1 - *(double *)vp2; // 警告,从double转换到int可能会丢失数据:0.5-0.4=0.1 转成整型:0,可能比较的时候会被认为是两个相等,从而造成错误
double tmp = *(double*)vp1 - *(double*)vp2;
if(tmp > 0)
return 1;
else if(tmp = 0)
return 0;
else
return -1;
}
void Show (int *p, int n)
{
for(int i = 0; i < n; i++)
{
printf("%d ",p[i]);
}
printf("\n");
}
void Show_D (double *p, int n)
{
for(int i = 0; i < n; i++)
{
printf("%.2f ",p[i]);//用来输出实数,保留小数点2位
}
printf("\n");
}
void main()
{
int arr[] = {1,5,2,8,3,6,4};
//对arr进行排序
double brr[] = {11.1,11.12,12.1,52.2,36.5,15.2,10.1};
//直接用库函数qsort,参数:数组名,数组元素个数,数组每个元素大小,函数指针
int len1 = sizeof(arr)/sizeof(arr[0]);
int len2 = sizeof(brr)/sizeof(brr[0]);
Show(arr,sizeof(arr)/sizeof(arr[0]));
qsort(arr,len1,sizeof(arr[0]),Com_int);
Show(arr,sizeof(arr)/sizeof(arr[0]));
Show_D(brr,sizeof(brr)/sizeof(brr[0]));
qsort(brr,len2,sizeof(brr[0]),Com_double);
Show_D(brr,sizeof(brr)/sizeof(brr[0]));//不能用int类型的Show函数
}
//8-26 动态内存使用的场景,在下一节会讲怎么用的
//1.需要大容量内存时
//2.在一个函数创建的内存在别的函数中还需要使用时
//3.在VS2022中需要使用变量作为数组的长度
void main()
{
//1.需要大容量内存时
//char arr[100000000000000000000] = "";//程序崩溃了
//因为局部变量:分配的内存区域在栈,很小(1M~10M)
//1000 0000个整数,至少需要40M内存
//printf("好了\n");
//char arr[1024*1024] = "";//一兆,VS的程序崩溃了,VScode没有。1024个字节是1K内存,1K*1K是1M内存,说明VS的char类型的内存略小于1M,但是在VScode中是可以的,说明VScode中char类型大于1M;不同平台会不一样。
//printf("好了\n");
//char arr[1000 * 1000] = "";//可以。略小于1M
//printf("好了\n");
//char arr[10*1000*1000] = "";//10兆,VScode的程序崩溃了
//printf("好了\n");
//2.在一个函数创建的内存在别的函数中还需要使用时
char *GetMemory()
{
char str[] = "梦想总是要有的,万一实现了呢";
return str;//已经被销毁
}
void main()
{
char *p = GetMemory();
printf("%s\n",p);
}
}
//8-27 动态内存使用
//如何创建动态内存:使用4个函数
//malloc:创建内存; 需要引用stdlib头文件,失败返回NULL,成功返回地址
//calloc:创建内存; 独有的小特性:会将每一个元素都初始化为0
//realloc:创建内存; 主要用于修改动态内存的大小,参数:指向之前已分配内存块的指针;新的大小(字节)
//free:释放内存,如果没有释放动态申请的内存,会出现内存泄漏(这是C/C++最麻烦的问题)
//内存泄漏:你申请了,但忘记释放,导致申请出去的内存别的程序无法再使用,导致可用的内存变少,设备速度越来越慢
//泄漏的内存什么时候会释放:1.程序(进程)结束了 2.关机(重启)
//void:没有,可以修饰返回值和参数列表
//void*:没有类型信息的指针,这个指针仅仅是记录地址
//1.需要创建100M内存
char *GetMemory()
{
char str[] = "梦想总是要有的,万一实现了呢";
return str;//已经被销毁
}
void main()
{
//malloc参数:需要分配的内存大小(以字节为单位)
void* p = malloc(100*1024*1024);
if(p == NULL)
printf("申请失败了\n");
printf("好了");
getchar();
free(p);
}
//2.申请100个int单元
char *GetMemory()
{
char* str = (char*)malloc(100 * sizeof(char));
strcpy(str,"梦想总是要有的,万一实现了呢");
return str;
}
void main()
{
//calloc参数:元素数量,每个元素的长度(以字节为单位)
//int *arr = (int*)calloc(n,sizeof(int));//arr可以看成是n个int类型的数组名
char *p = GetMemory();
printf("%s\n",p);
free(p);
}
//3.申请10个int单元
void main()
{
int n = 10;
//int arr[n];//VS2022中变量不能作为数组长度,但在VScode中可以
int *arr = (int *)malloc(n*sizeof(int));
for(int i = 0; i < n; i++)
arr[i] = i;
//使用过程中,发现内存不够,需要2n个单元,就要使用realloc函数
arr = (int *)realloc(arr,2*n*sizeof(int));
for(int i = 0; i < 2; i++)
arr[i] = i;
free(arr);
}