知识点1【函数指针 作为 函数的形参】
案例1:
#include<stdio.h>
int my_add(int a,int b)
{
return a+b;
}
int my_sub(int a,int b)
{
return a-b;
}
int my_mul(int a,int b)
{
return a*b;
}
//定义一个函数 实现上述函数的功能
int my_calc(int a,int b, int (*fun_pointer)(int,int) )
{
return fun_pointer(a,b);
}
void test01()
{
printf("%d\n",my_calc(10,20,my_add));
printf("%d\n",my_calc(10,20,my_sub));
printf("%d\n",my_calc(10,20,my_mul));
}
int main(int argc,char *argv[])
{
test01();
return 0;
}
运行结果:
知识点2【malloc函数 和 free函数】
malloc函数
#include<stdlib.h>
void *malloc(unsigned int num_size);
形参:num_size需要申请空间大小的字节数。
返回值:
成功:返回空间的起始地址
失败:NULL
特点:
1、对于malloc的返回值 一般要强制类型转换
2、malloc申请的空间 内容不确定 一般使用memset进行清空
3、多次调用malloc 第1次malloc 和 第2次malloc的地址不一定连续
free函数
void free(void *addr);
释放堆区空间
案例1:从堆区申请 一个int空间
void test02()
{
int *addr = NULL;
addr = (int *)malloc(sizeof(int));
if(addr == NULL)//申请失败了
{
printf("malloc err\n");
return;
}
printf("*addr=%d\n", *addr);//不确定的值
//对堆区空间 清0
memset(addr, 0, sizeof(int));
printf("*addr=%d\n", *addr);//0
//对addr的空间 就行写 或 读
*addr = 1000;//写
printf("*addr=%d\n", *addr);//1000 读
//释放堆区空间 空间使用权限的回收 是否对空间内容清0 这是不确定的
free(addr);
}
int main(int argc,char *argv[])
{
test02();
return 0;
}
运行结果:案例2:从堆区申请一个数组 数组的大小 由用户决定
1、从键盘获取 用户要申请的数组大小
2、根据大小 从堆区申请空间
3、对空间的读写操作
4、释放该空间
void test03()
{
int n = 0;
int i=0;
int *arr=NULL;
//1、获取用户大小
printf("请输入元素的个数:");
scanf("%d", &n);
//2、根据大小从堆区申请空间
arr = (int *)malloc(n*sizeof(int));
if(NULL == arr)
{
//perror 错误输出
perror("mallac");
return;
}
//对arr的读写操作
printf("请输入%d个int数据\n",n);
for(i=0;i<n; i++)
{
scanf("%d", arr+i);
}
//遍历数组
for(i=0;i<n;i++)
{
printf("%d ", arr[i]);
}
//释放空间
free(arr);
}
int main(int argc,char *argv[])
{
test03();
return 0;
}
案例3:从堆区申请一个数组 数组的大小 由用户决定(函数版本)
int get_n(void)
{
int n = 0;
printf("请输入元素的个数:");
scanf("%d", &n);
return n;
}
int* get_addr(int n)
{
return (int *)malloc(n*sizeof(int));
}
void my_input_array(int *arr, int n)
{
int i=0;
//记得将arr指向的空间清0
memset(arr,0,n*sizeof(int));
//获取键盘输入
printf("请输入%d个int数据\n",n);
for(i=0;i<n; i++)
{
scanf("%d", arr+i);
}
}
void my_print_array(int *arr, int n)
{
int i=0;
for(i=0;i<n;i++)
{
printf("%d ", arr[i]);
}
printf("\n");
}
void test04()
{
int *arr=NULL;
int n = 0;
//得到用户输入的元素个数
//1、获取用户大小
n = get_n();
//定义函数 给arr申请堆区空间
arr = get_addr(n);
if(arr == NULL)
{
perror("get_addr");
return;
}
//对空间读写操作
my_input_array(arr, n);
//对空间数组遍历
my_print_array(arr, n);
//释放空间
free(arr);
}
int main(int argc,char *argv[])
{
test04();
return 0;
}
运行结果:
知识点3【calloc函数】
#include<stdlib.h>
void * calloc(size_t nmemb,size_t size);
参数:
1、nmemb 申请的数据块数
2、size 每一块大小
3、所以申请总大小=nmemb * size
返回值:
成功:返回空间的起始地址
失败:返回NULL
特点:申请的空间自动清零
案例:
void test04()
{
int n = 0;
int i=0;
int *arr=NULL;
//1、获取用户大小
printf("请输入元素的个数:");
scanf("%d", &n);
//2、根据大小从堆区申请空间
#if 0
arr = (int *)malloc(n*sizeof(int));
if(NULL == arr)
{
//perror 错误输出
perror("mallac");
return;
}
memset(arr,0,n*sizeof(int));//清零
#endif
#if 1
arr=(int *)calloc(n, sizeof(int));//自动清零 不需要使用memset
if(NULL == arr)
{
//perror 错误输出
perror("calloc");
return;
}
#endif
//对arr的读写操作
printf("请输入%d个int数据\n",n);
for(i=0;i<n; i++)
{
scanf("%d", arr+i);
}
//遍历数组
for(i=0;i<n;i++)
{
printf("%d ", arr[i]);
}
//释放空间
free(arr);
}
知识点4【realloc动态追加或减少空间】
#include<stdlib.h>
void* realloc(void *s, unsigned int newsize);
功能:
在原先s指向的内存基础上重新申请内存,新的内存的大小为 new_size 个 字节,如果原先内存后面有足够大的空间,就追加,如果后边的内存不 够用,则realloc函数会在堆区找一个newsize个字节大小的内存申请,将原先内存中的内容拷贝过来,然后释放原先的内存,最后返回新内存的地址。
参数:s:原先开辟内存的首地址 newsize:新申请的空间的大小
返回值:新申请的内存的首地址
注意:一定要保存 realloc的返回值
void test06()
{
int *arr = NULL;
int n = 0;
int i=0;
int n_new = 0;
//1、获取用户大小
printf("请输入元素的个数:");
scanf("%d", &n);
arr=(int *)calloc(n, sizeof(int));//自动清零 不需要使用memset
if(NULL == arr)
{
//perror 错误输出
perror("calloc");
return;
}
printf("请输入%d个int数据\n",n);
for(i=0;i<n; i++)
{
scanf("%d", arr+i);
}
//遍历数组
for(i=0;i<n;i++)
{
printf("%d ", arr[i]);
}
//再追加5个元素
printf("请输入新增的元素个数:");
scanf("%d", &n_new);
arr = (int *)realloc(arr, (n+n_new)*sizeof(int));
printf("请输入新增的%d个int数据\n",n_new);
for(i=n;i<(n+n_new); i++)
{
scanf("%d",arr+i);
}
for(i=0;i<(n+n_new);i++)
{
printf("%d ", arr[i]);
}
printf("\n");
free(arr);
}
int main(int argc,char *argv[])
{
test06();
return 0;
}
运行结果:知识点5【堆区空间使用的注意事项】
void test08()
{
int *p2 = NULL;
int *p3 = NULL;
//1、指向堆区空间的指针变量 不要随意的更改指向
int *p=(int *)calloc(1,sizeof(int));
int num = 10;
p = #//p指向num 导致calloc申请的空间泄露
//2、不要操作已经释放的空间
p2 = (int *)calloc(1,sizeof(int));
*p2 = 1000;
//释放该空间
free(p2);
printf("*p2 = %d\n", *p2);//不确定
//3、不要对堆区空间重复释放
p3 = (int *)calloc(1,sizeof(int));
free(p3);
free(p3);//多次释放
}
知识点6【防止多次释放】
void test09()
{
int *p = (int *)calloc(1,sizeof(int));
if(p != NULL)//防止多次释放
{
free(p);
p=NULL;
}
if(p != NULL)
{
free(p);
p=NULL;
}
}
知识点7【字符串处理函数】
只要是以str开头的函数 都是遇到’\0’结束
#include<string.h>
1、strlen测量字符换长度
size_t strlen(const char *s)
//s:被测量的字符串首元素地址
//返回值为 字符串的长度 不包含’\0’
//const char *s strlen函数 不会通过s修改s指向的空间内容
案例:
void test01()
{
char buf1[128]="hehehe";
char buf2[]="hehehe";
char buf3[]="hehe\0he";
// \123 代表一个字符 \hhh 八进制转义h: 0~7
//\\表示'\'
char buf4[]="hehe\123\\he";
//\\x2f表示一个字符 \xdd 十六进制转义 d:0~9 a~f
char buf5[]="hehe\x2fhe";
printf("%d\n",sizeof(buf1));//126
printf("%d\n",strlen(buf1));//6
printf("%d\n",sizeof(buf2));//7
printf("%d\n",strlen(buf2));//6
printf("%d\n",sizeof(buf3));//8
printf("%d\n",strlen(buf3));//4
printf("%d\n",sizeof(buf4));//9
printf("%d\n",strlen(buf4));//8
printf("%s\n",buf4);
printf("%d\n",sizeof(buf5));//8
printf("%d\n",strlen(buf5));//7
char buf6[]="\0hehe\0hehe";
printf("%d\n",strlen(buf6));//0
return;
}
作业:自定义一个my_strlen函数测量字符串长度(不能在函数里面使用strlen)
int my_strlen(const char *s);
2、strcpy strncpy字符串拷贝(重要)
strcpy
原型:char *strcpy( char *dest, const char *src )
功能:把src所指向的字符串复制到dest所指向的空间中
返回值:返回dest字符串的首地址
注意:遇到’\0’会结束,只是’\0’也会拷贝过去
void test02()
{
char src[]="hello string";
//保证dst足够大
char dst[128]="";
strcpy(dst,src);
printf("dst=%s\n",dst);//"hello string"
}
void test02()
{
char src[]="hello\0string";
//保证dst足够大
char dst[128]="";
strcpy(dst,src);
printf("dst=%s\n",dst);//"hello"
}
实现strcpy
char *my_strcpy(char *dst,const char *src)
{
#if 0
do
{
*dst = *src;
dst++;
src++;
}while(*src != '\0');
*dst='\0';
#endif
while(*dst++ = *src++);
}
void test02()
{
char src[]="hello\0string";
//保证dst足够大
char dst[128]="";
my_strcpy(dst,src);
printf("dst=%s\n",dst);//"hello"
}
strncpy
原型:char *strncpy( char *dest, const char *src,int num)
功能:把src指向字符串的前num个复制到dest所指向的空间中
返回值:返回dest字符串的首地址
注意:’\0’不拷贝
void test03()
{
char src[]="hello string";
//保证dst足够大
char dst[128]="";
strncpy(dst,src,3);
printf("dst=%s\n",dst);//"hel"
}
void test03()
{
char src[]="hello";
//保证dst足够大
char dst[128]="";
strncpy(dst,src,30);
printf("dst=%s\n",dst);//"hello"
}
3、strcat字符串的拼接
char *strcat(char *dest, const char *src);
将src的字符串 拼接到 dst的末尾(dst第一个’\0’的位置)
void test04()
{
char src[]="world";
char dst[128]="hello";
strcat(dst,src);
printf("%s\n",dst);//"helloworld"
}
void test04()
{
char src[]="wor\0ld";
char dst[128]="hello";
strcat(dst,src);
printf("%s\n",dst);//"hellowor"
}
strncat拼接前n个
void test04()
{
char src[]="world";
char dst[128]="hello";
strncat(dst,src,2);
printf("%s\n",dst);//"hellowo"
}
作业:自定义my_strcat函数 不许使用 strcat
char *my_strcat(char *dest, const char *src);
4、strcmp字符串的比较 (整个字符串的比较)
int strcmp(const char *s1, const char *s2);
功能:将s1和s2指向的字符串 逐个字符比较
返回值:
>0: 表示s1 > s2
<0: 表示s1 < s2
==0: 表示s1 == s2
void test05()
{
char s1[]="hehe haha";
char s2[]="hehe xixi";
char s3[]="hehe haha";
if(strcmp(s1,s2) >0 )
{
printf("s1 > s2\n");
}
else if(strcmp(s1,s2) <0 )
{
printf("s1 < s2\n");
}
else if(strcmp(s1,s2) == 0)
{
printf("s1 == s2\n");
}
if(strcmp(s1,s3) >0 )
{
printf("s1 > s3\n");
}
else if(strcmp(s1,s3) <0 )
{
printf("s1 < s3\n");
}
else if(strcmp(s1,s3) == 0)
{
printf("s1 == s3\n");
}
}
运行结果:strncmp 字符串局部比较
void test05()
{
char s1[]="hehe haha";
char s2[]="hehe xixi";
if(strncmp(s1,s2,4) >0 )
{
printf("s1 > s2\n");
}
else if(strncmp(s1,s2,4) <0 )
{
printf("s1 < s2\n");
}
else if(strncmp(s1,s2,4) == 0)
{
printf("s1 == s2\n");
}
}
运行结果:5、strchr字符查找函数
char *strchr(const char *s, int c);
//从字符串s中查找第一次c字符出现的地址
//没有找到 返回NULL
void test06()
{
char str[]="www.1000phone.com";
char *ret = NULL;
ret = strchr(str,'o');
if(ret != NULL)
{
*ret = '#';
}
printf("str=%s\n",str);//"www.1000ph#ne.com";
}
(了解)
void test06()
{
char str[]="www.1000phone.com";
char *ret = NULL;
while((ret = strchr(str,'o')) && (*ret = '#') );
printf("str=%s\n",str);//"www.1000ph#ne.c#m";
}
重要 啥都写 了解
6、strstr字符串查找
char *strstr(const char *s1, const char *s2);
//从s1中查找字符串s2 返回第一次s2出现的地址
//查找失败 返回NULL
void test07()
{
char s1[]="www.sex.777.sex.com";
char s2[]="sex";
char *ret = NULL;
ret = strstr(s1,s2);
if(ret == NULL)
{
return;
}
printf("%s\n",ret);//"sex.777.sex.com"
}
void test07()
{
char s1[]="www.sex.777.sex.com";
char s2[]="sex";
char *ret = NULL;
while(1)
{
ret = strstr(s1,s2);
if(ret == NULL)
{
break;
}
memset(ret,'#', 3);
}
printf("%s\n",s1);//"www.###.777.###.com"
}