//头文件函数声明
//防止头文件重复包含(相互包含陷入包含死循环)
#pragma once
//兼容C++编译器
//如果是C++编译器,按c标准编译
#ifdefine __cplusplus //C语言编译器中已有的宏,不是自定义宏
extern "C"
{
#endif
//接口函数
#ifdefine __cplusplus
extern "C"
}
#endif
//在a.cpp文件中调用b.c文件中函数,而又不想将b.c文件改成b.cpp文件,则需要在b.h文件加入上述代码,让其按照c标准编译
CS:客户端服务器
BS:浏览器和服务器(可以认为其是一种特殊的CS)
学习标准
第一套api接口
//初始化socket句柄的接口
int socket_client_init(void **handle);
//发送socket网络报文
int socket_client_send(void *handle, unsigned char *buf, int buf_len);
//接收socket网络报文
int socket_client_recv(void *handle, unsigned char *buf, int *buf_len);
//释放socket句柄资源
int destory_socket(void *handle);
第二套api接口
//初始化socket句柄的接口
int socket_client_init(void **handle);
//发送socket网络报文
int socket_client_send(void *handle, unsigned char *buf, int buf_len);
//接收socket网络报文
int socket_client_recv(void *handle, unsigned char **buf, int *buf_len);
//
socket_client_free(unsigned char **buf);
//释放socket句柄资源
int destory_socket(void **handle);
void类型
①函数参数为空,定义函数时,可以用void修饰;
②函数没有返回值;
③不能定义void类型的普通变量:void a;//err,无法确定类型,不同类型分配空间不一样(数据类型本质,固定内存块大小别名)
④可以定义void *变量: void * p;//合法,32位机器占4个字节,64位机器占8个字节
⑤void *p 万能指针,函数返回值,函数参数。
内存四区
//"abcdef"保存在字符串常量区
char *get_str1()
{
char *p ="abcdef";//p指向文字常量区
return p;
}
char *get_str2()
{
char str[] ="abcdef";//str空间为栈区,将文字常量区的内容拷贝到str空间,此函数调用完成后str所指向的内存区域被释放
return str;
}
char *get_str3()
{
char *tmp = (char *)malloc(100);//堆区,由程序员释放
if(tmp == NULL)
{
return NULL;
}
strcpy(tmp,"abcdef");
return tmp;
}
int main(void)
{
char *p1 =NULL;
char *p2 =NULL;
char *p3 =NULL;
p1=get_str1();
printf("%s\n",p1);
p2=get_str2();
//get_str2()运行完毕,str空间自动回收,str的空间内容未知,有可能保留之前的内容,也有可能是乱码
printf("%s\n",p2);
p3=get_str3();
if(p3!=NULL)
{
printf("%s\n",p3);
free(p3);//由程序员释放
p3=NULL;//养成良好习惯
}
return 0;
}
函数的调用模型:先进后出
栈的生长方向和内存的存放方向:栈的生长方向为由高到底,而内存以及堆的生长方向由底到高
程序验证
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
char *get_str1()
{
char *tmp = (char *)malloc(100);//堆区,由程序员释放
if(tmp == NULL)
{
return NULL;
}
strcpy(tmp,"abcdef");
return tmp;
}
char *get_str2()
{
char *tmp = (char *)malloc(100);//堆区,由程序员释放
if(tmp == NULL)
{
return NULL;
}
strcpy(tmp,"taylen");
return tmp;
}
int main()
{
//栈的生长方向
int a;
int b;
printf("栈的生长方向\n");
printf("&a: %p\n", &a);
printf("&b: %p\n", &b);
//堆的生长方向
char * p1=NULL;
char * p2=NULL;
p1 = get_str1();
p2 = get_str2();
printf("堆的生长方向\n");
printf("p1的地址:%p\n",p1);
printf("p1+1地址:%p\n",p1+1);
printf("p1的地址:%p\n",p1);
printf("p2的地址:%p\n",p2);
free(p1);
free(p2);
//内存的生长方向
char buf[4];
printf("内存的生长方向\n");
printf("buf的地址: %p\n", &buf[0]);
printf("buf+1地址: %p\n", &buf[1]);
return 0;
}
输出结果:
①栈区地址生长方向:地址由上往下递减
②堆区地址生长方向:地址由下往上递增
③数组buf,buf+1地址永远递增
指针易错点
①写内存时,一定要内存可写
char *buf1 = "abcdefg";//文字常量区,内存不可改
buf1[2] = '1';//err
char buf2[] = "abcdefg";/
buf2[2] = '1';//ok
②不允许向NULL和未知非法地址拷贝内存
指针强化
如何定义合适类型的指针变量:某个变量地址需要定义一个怎样类型的变量保存;在这个类型的基础上加一个*
int b;
int *q = &b;
int ** t =&q
如果想通过函数形参改变实参的值,必须传地址:
1、值传递,形参的任何修改不会影响到实参
2、地址传递,形参(通过*操作符号)的任何修改会影响到实参
主调函数与被调函数:
a)主调函数可把堆区、栈区、全局数据内存地址传给被调函数
b)被调函数只能返回堆区、全局数据
内存分配:
a)指针做函数参数,是输入与输出特性的(输入:主调函数分配内存;输出:被调函数分配内存)
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
void fun1(char *p /*in*/)
{
if(p == NULL)
{
return;
}
//给p指向的内存区域拷贝
strcpy(p,"PointerAsInput");
}
void fun2(char **p /*out*/,int *len)
{
if(p == NULL)
{
return;
}
char *tmp = (char *)malloc(100);
if(tmp == NULL)
{
return;
}
strcpy(p,"PointerAsOutput");
//简洁赋值
*p =tmp;
*len =strlen(tmp);
}
int main(void)
{
//输入,主调函数分配内存
char buf[100]={0};
fun1(buf);
printf("buf = %s\n",buf);
//输出,被调用函数分配内存,地址传递
char *p = NULL;
int len = 0;
fun2(&p);
if(p!=NULL)
{
printf("p = %s,len = %d\n",p,len);
free(p);
p=NULL;
}
system("pause");
return 0;
}
字符串
/*C语言没有字符串类型,通过字符数据模拟
C语言字符串,以字符'\0'结尾,数字0*/
//不指定⻓长度,C编译器会⾃自动帮程序员求元素的个数
//buf1是⼀一个数组 不是⼀一个以0结尾的字符串
char buf1[] = {'a', 'b', 'c', 'd'};
printf("buf1 = %s\n",buf1) //结果会是abcd+乱码
//用字符串初始化字符数组 ,常用
char buf2[] = "abcd"; //buf2 作为字符数组 有5个字节
// 作为字符串有 4个字节
int len = strlen(buf2);
printf("buf2字符的⻓长度:%d \n", len); //4
//buf3 作为数组 数组是⼀一种数据类型 本质(固定⼩小⼤大内存块的别名)
int size = sizeof(buf2); //
printf("buf2数组所占内存空间⼤大⼩小:%d \n", size); //5
指针和字符串数组名是否等价?
char buf[] = "abcdefg";
char *p =NULL;
p = buf;
p++;//没问题
buf++;//报错
/*buf只是一个常量,不能修改,主要是为了确保最终内存可以回收*/
const的使用
const声明的变量只能被读 ,且必须被初始化。但可以通过指针间接修改。
1)const声明变量为只读
const int a = 10;
a=100;//err
char buf[100]="abcd";
const char *p=buf;
char const *p=buf;//修饰*,指针指向能变,指针指向的内存不能变
//p[0]='1';//err
p = "123456";//ok
char *const p1 = buf;//修饰指针变量,指针指向的内存能变,指针指向不能变
//p1="123456";//err
p1[0]='1';//ok
const char* const p2=buf;//p2,只读
二级指针
如果一个指针变量存放的又是另一个指针变量的地址,则称这个指针变量为指向指针的指针 变量。也称为“二级指针”。
指针数组:
//指针数组,指针的数组,它是一个数组,每个元素都是char*
char *p[] = {"1111","0000","aaaa","bbbb"};
char **q = {"1111","0000","aaaa","bbbb"};//err
//只有在作为函数参数时两者可通用
二级指针做函数参数输出特性
#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
int getMem(char *p)
{
p = (char *)malloc(sizeof(char) * 100);
if (p == NULL)
{
return -1;
}
//p = "abcdef";
strcpy(p, "abcdef");
printf("p = %s\n", p);
return 0;
}
int main(void)
{
char *p = NULL;
int ret = 0;
ret = getMem(p);
if (ret != 0)
{
printf("getMem err: %d\n", ret);
return ret;
}
printf("p = %s", p);
printf("\n");
system("pause");
return 0;
}
//输出结果
/*
p = abcdef
p = (null)
*/
上面的例子,在执行语句ret = getMem(p)时,只是值传递,拷贝了实参p的值赋值给形参p,即形参p的值一开始即为NULL,随后通过malloc分配了内存,并将该内存中填入“abcd”,但其并未与实参p有实际对应关系。相应的正确代码如下(地址传递,形参修改会影响到实参):
#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
int getMem2(char **p)
{
if (p == NULL)
{
return -1;
}
char * tmp;
tmp = (char *)malloc(sizeof(char) * 100);
if (tmp == NULL)
{
return -2;
}
//p = "abcdef";
strcpy(tmp, "abcdef");
*p = tmp;
return 0;
}
int main(void)
{
char *p = NULL;
int ret = 0;
ret = getMem2(&p);
if (ret != 0)
{
printf("getMem err: %d\n", ret);
return ret;
}
printf("p = %s", p);
if (p != NULL)
{
free(p);
p = NULL;
}
printf("\n");
system("pause");
return 0;
}
对应的内存四区图如下:
二级指针输入特性:
第一种输入模型
char *myArray[] = {"aaaaaa", "ccccc", "bbbbbb", "111111"};
void printMyArray(char **myArray, int num);
void sortMyArray(char **myArray, int num);
#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
void print_array(char **p, int n)
//void print_array(char *p[], int n)与上面相同
{
int i = 0;
for (i = 0; i < 4; i++)
{
printf("%s, ", p[i]);
}
printf("\n");
}
void sort_array(char *p[], int n)
{
char *tmp = NULL;
for (int i = 0; i < n - 1; i++)
{
for (int j = i + 1; j < n; j++)
{
if (strcmp(p[i], p[j]) > 0)
{
tmp = p[j];
p[j] = p[i];
p[i] = tmp;
}
}
}
}
int main(void)
{
//指针数组
char *p[] = { "111111","000000","bbbbbb","aaaaaa" };
//char **q = { "111111","000000","bbbbbb","aaaaaa" };err
int n = sizeof(p) / sizeof(p[0]);
printf("n = %d\n", n);
printf("排序前\n");
print_array(p, n);
//选择法排序
sort_array(p, n);
printf("排序后\n");
print_array(p, n);
system("pause");
return 0;
}
第二种输入模型:
char myArray[10][30] = {"aaaaaa", "ccccc", "bbbbbbb", "1111111111111"};
void printMyArray(char myArray[10][30], int num);
void sortMyArray(char myArray[10][30], int num);
二维数组,数组名代表首行地址。首行地址和首行首元素地址有区别,但值是一样的。
区别:步长不一样
#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
//二维数组作为函数参数时,函数参数不能写成如下形式
/*
void print_array(char **a, int n)
{
printf("a :%d,a +1 :%d\n", a, a + 1);//二维数组退化为指针,步长已发生改变
int i = 0;
for (i = 0; i < n; i++)
{
printf("%s, ", a[i]);
}
printf("\n");
}
*/
void print_array(char a[][20] ,int n)//20即为步长
{
printf("a :%d,a +1 :%d\n", a, a + 1);
int i = 0;
for (i = 0; i < n; i++)
{
printf("%s, ", a[i]);
}
printf("\n");
}
void sort_array(char a[][20], int n)
{
char tmp[20];
for (int i = 0; i < n - 1; i++)
{
for (int j = i + 1; j < n; j++)
{
if (strcmp(a[i], a[j]) > 0)
{
strcpy(tmp, a[i]);
strcpy(a[i], a[j]);
strcpy(a[j], tmp);
}
}
}
}
int main(void)
{
char a0[20] = "000000";
char a1[20] = "111111";
char a2[20] = "bbbbbb";
char a3[20] = "cccccc";
//二维数组第一个[]可以不填,但条件是必须要初始化
char a[][20] = { "111111","000000","bbbbbb","aaaaaa" };
int n = sizeof(a) / sizeof(a[0]);
printf("a0 :%d,a0+1 :%d\n", a0, a0 + 1);
printf("&a0:%d,&a0+1:%d\n", &a, a + 1);
printf("a :%d,a +1 :%d\n", a, a + 1);
printf("&a:%d,&a+1:%d\n", &a, &a + 1);
printf("排序前\n");
print_array(a, n);
//选择法排序
sort_array(a, n);
printf("排序后\n");
print_array(a, n);
system("pause");
return 0;
}
/*
a0 :11532704,a0+1 :11532705
&a0:11532532,&a0+1:11532552
a :11532532,a +1 :11532552
&a:11532532,&a+1:11532612
排序前
a :11532532,a +1 :11532552
111111, 000000, bbbbbb, aaaaaa,
排序后
a :11532532,a +1 :11532552
000000, 111111, aaaaaa, bbbbbb,
*/
第三种输入模型
char **myArray = NULL;
char **getMem(int num);
void printMyArray(char **myArray, int num);
void sortMyArray(char **myArray, int num);
void arrayFree(char **myArray, int num);
#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
int main(void)
{
char *p0 = NULL;
p0 = malloc(100);
strcpy(p0, "abcdefg");
int i = 0;
char *p[3] = { 0 };
for (i = 0; i < 10; i++)
{
p[i] = malloc(100);
strcpy(p[i], "abcdefg");
}
int a[3];
int *q = (int *)malloc(3 * sizeof(int));//相当于int q[10]
//动态分配一个数组,每个元素都是char*
//char*buf[3]
int n = 3;
char **buf = (char **)malloc(n * sizeof(char *));//相当于char *buf[3],buf指向堆区
if (buf == NULL)
{
return -1;
}
//strcpy(buf[0], "abcdefg");
for (i = 0; i < n; i++)
{
buf[i] = (char *)malloc(30 * sizeof(char));
char str[30];
sprintf(str, "test%d%d", i, i);
strcpy(buf[i], str);
}
for (i = 0; i < n; i++)
{
printf("%s, ", buf[i]);
}
printf("\n");
for (i = 0; i < n; i++)
{
free(buf[i]);
buf[i] = NULL;
}
if (buf != NULL)
{
free(buf);
}
system("pause");
return 0;
}
内存四区图如下:
封装函数后代码如下:
#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
char **getMem(int n)
{
int i = 0;
char **buf = (char **)malloc(n * sizeof(char *));//相当于char *buf[3],buf指向堆区
if (buf == NULL)
{
return NULL;
}
//strcpy(buf[0], "abcdefg");
for (i = 0; i < n; i++)
{
buf[i] = (char *)malloc(30 * sizeof(char));
char str[30];
sprintf(str, "test%d%d", i, i);
strcpy(buf[i], str);
}
return buf;
}
void print_buf(char **buf,int n)
{
int i = 0;
for (i = 0; i < n; i++)
{
printf("%s, ", buf[i]);
}
}
void free_buf(char **buf,int n)
{
int i = 0;
for (i = 0; i < n; i++)
{
free(buf[i]);
buf[i] = NULL;
}
if (buf != NULL)
{
free(buf);
buf = NULL;
}
}
int main(void)
{
char **buf = NULL;
int n = 3;
buf = getMem(n);
if (buf == NULL)
{
printf("getMem err\n");
return -1;
}
print_buf(buf,n);
free_buf(buf, n);
buf = NULL;
printf("\n");
system("pause");
return 0;
}
内存四区图如下:
数组类型定义
数组类型:由元素个数和元素类型对应,可以通过typedef定义一个数字类型
typedef int A[8];//代表数组类型,它是一个类型,不是变量
A b;//int b[8],去掉typedef,b替换到A的位置
数组指针和指针数组
指针数组:
char *point_array[4];
(char *)point_array[4];
#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
//argc:传参的个数(包含可执行程序)
//argv:指针数组,指向输入的参数
int main(int argc,char *argv[])
{
/*
指针数组与数组指针
指针数组:它是数组,每个元素都是指针
*/
//指针数组,[]比*的优先级高
char *a[] = { "aaaaa","bbbbb","ccccc" };
int i = 0;
printf("argc=%d\n", argc);
for (i = 0; i < argc; i++)
{
printf("%s\n", argv[i]);
}
printf("\n");
system("pause");
return 0;
}
数组指针:是一个指针,指向一个数组。(一个指针)
int (*array_point)[4];
1、先定义数组类型,根据类型定义指针变量
#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
int main(void)
{
//数组指针,它是指针,指向一个数组的指针
//数组指针,指向一维数组的整个数组,而不是首元素地址
//定义数组指针变量
int i = 0;
int a[10] = { 0 };
//1、先定义数组类型,根据类型定义指针变量
typedef int A[10];//A数组类型,10代表步长
A *p = NULL;//p数组指针类型变量
//p = a;//会有警告
p = &a;//ok
printf("p:%d,p+1:%d\n", p, p + 1);
for (i = 0; i < 10; i++)
{
(*p)[i] = i + 1;
}
for (i = 0; i < 10; i++)
{
printf("%d", (*p)[i]);
}
printf("\n");
system("pause");
return 0;
}
2、先定义数组指针类型,根据类型定义变量
#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
int main(void)
{
int i = 0;
int a[10] = { 0 };
//1、先定义数组指针类型,根据类型定义变量
//和指针数组写法很类似,多了()
//()与[]优先级一样,从左往右
//指向数组的指针,它有typedef,所以它是一个数组指针类型
typedef int(*P)[10];
P q;//数组指针变量
q = &a;
for (i = 0; i < 10; i++)
{
(*q)[i] = i + 1;
}
for (i = 0; i < 10; i++)
{
printf("%d", (*q)[i]);
}
printf("\n");
system("pause");
return 0;
}
3、直接定义数组指针变量
#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
int main(void)
{
int i = 0;
int a[10] = { 0 };
//3、直接定义数组指针变量
int(*q)[10];//q数组指针变量
q = &a;
for (i = 0; i < 10; i++)
{
(*q)[i] = i + 1;
}
for (i = 0; i < 10; i++)
{
printf("%d", (*q)[i]);
}
printf("\n");
system("pause");
return 0;
}
二维数组的使用
#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
int main(void)
{
int a1[3][4] = { {1,2,3,4},{5,6,7,8},{9,10,11,12} };//不常用
int a2[3][4] = { 1,2,3,4,5,6,7,8,9,10,11,12 };
int a3[][4] = { 1,2,3,4,5,6,7,8,9,10,11,12 };
int i = 0;
int j = 0;
for(i = 0; i < 3; i++)
{
for (j = 0; j < 4; j++)
{
printf("%d ,", a3[i][j]);
}
printf("\n");
}
//二维数组数组名代表0行的首地址(区别于第0行首元素地址,虽然值一样)
//它们步长不一样
printf("a:%d, a+1:%d\n", a3, a3 + 1);
printf("%d, %d\n", *(a3 + 0), *(a3 + 1));//第0行与第1首元素地址
printf("%d, %d\n", *(a3 + 0),*(a3 + 0)+1);//第0行首元素地址,第0行第1列元素地址
printf("%d, %d\n", a3[0], a3[1]);
//a3:代表第0行首地址
//a3+i:->&a[i],代表第i行首地址
//*(a3+i)->a[i]:代表第0行首元素地址
//*(a3+i)+j->&a[i][j]:第i行第j列元素地址
//*(*(a3+i)+j)->a[i][j]=,第i行第j列元素值
printf("\n");
system("pause");
return 0;
}
数组指针与二维数组结合
#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
int main(void)
{
int a[][6] = { 1,2,3,4,5,6,7,8,9,10,11,12 };
//2个a[4]的一维数组
//定义数组指针变量
//指向一维数组的整个数组首地址
int(*p)[6];
//p=&a;//整个二维数组首地址p=a;
p = a;//第0行首地址,p等价子二维数组名
printf("p:%d,p+1:%d\n", p, p + 1);//6*4=24
int i = 0;
int j = 0;
int ni = sizeof(a) / sizeof(a[0]);
int nj = sizeof(a[0]) / sizeof(a[0][0]);
printf("%d,%d\n", ni, nj);
for (i = 0; i < ni; i++)
{
for (j = 0; j < nj; j++)
{
printf("%d ", p[i][j]);
//printf("%d ",*(*(p+i)+j));//可读性不好
}
printf("\n");
}
printf("\n");
system("pause");
return 0;
}
二维数组做函数形参
#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
typedef int(*P)[4];
void printArray1(int a[3][4])//第二个[]中的参数一定要填写,决定步长
{
int i = 0;
int j = 0;
for (i = 0; i < 3; i++)
{
for (j = 0; j < 4; j++)
{
printf("%d ", a[i][j]);
}
printf("\n");
}
}
//步长a+1,跳一行,4*4=16个字节
void printArray2(int a[][4])//第二个[]中的参数一定要填写,决定步长
{
int i = 0;
int j = 0;
for (i = 0; i < 3; i++)
{
for (j = 0; j < 4; j++)
{
printf("%d ", a[i][j]);
}
printf("\n");
}
}
//步长a+1,跳4个字节
void printArray3(int **a)//err,指针步长不一样
{
printf("%d,%d", a, a + 1);
/*
int i = 0;
int j = 0;
for (i = 0; i < 3; i++)
{
for (j = 0; j < 4; j++)
{
printf("%d ", a[i][j]);
}
printf("\n");
}
*/
}
void printArray4(int (*a)[4])//err,指针步长不一样
{
int i = 0;
int j = 0;
for (i = 0; i < 3; i++)
{
for (j = 0; j < 4; j++)
{
printf("%d ", a[i][j]);
}
printf("\n");
}
}
void printArray5(P a)//err,指针步长不一样
{
int i = 0;
int j = 0;
for (i = 0; i < 3; i++)
{
for (j = 0; j < 4; j++)
{
printf("%d ", a[i][j]);
}
printf("\n");
}
}
int main(void)
{
int a[][4] = { 1,2,3,4,5,6,7,8,9,10,11,12 };
//printArray1(a);//ok
//printArray2(a);//ok
//printArray3(a);//err,指针步长不一样
printArray4(a);//ok
printArray5(a);//ok
printf("\n");
system("pause");
return 0;
}
二维数组做函数形参
#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
typedef int(*P)[4];
void printArray1(int a[3][4])//第二个[]中的参数一定要填写,决定步长
{
int i = 0;
int j = 0;
for (i = 0; i < 3; i++)
{
for (j = 0; j < 4; j++)
{
printf("%d ", a[i][j]);
}
printf("\n");
}
}
//步长a+1,跳一行,4*4=16个字节
void printArray2(int a[][4])//第二个[]中的参数一定要填写,决定步长
{
int i = 0;
int j = 0;
for (i = 0; i < 3; i++)
{
for (j = 0; j < 4; j++)
{
printf("%d ", a[i][j]);
}
printf("\n");
}
}
//步长a+1,跳4个字节
void printArray3(int **a)//err,指针步长不一样
{
printf("%d,%d", a, a + 1);
/*
int i = 0;
int j = 0;
for (i = 0; i < 3; i++)
{
for (j = 0; j < 4; j++)
{
printf("%d ", a[i][j]);
}
printf("\n");
}
*/
}
void printArray4(int (*a)[4])
{
int i = 0;
int j = 0;
for (i = 0; i < 3; i++)
{
for (j = 0; j < 4; j++)
{
printf("%d ", a[i][j]);
}
printf("\n");
}
}
void printArray5(P a)
{
int i = 0;
int j = 0;
for (i = 0; i < 3; i++)
{
for (j = 0; j < 4; j++)
{
printf("%d ", a[i][j]);
}
printf("\n");
}
}
int main(void)
{
int a[][4] = { 1,2,3,4,5,6,7,8,9,10,11,12 };
//printArray1(a);//ok
//printArray2(a);//ok
//printArray3(a);//err,指针步长不一样
printArray4(a);//ok
printArray5(a);//ok
printf("\n");
system("pause");
return 0;
}
结构体相互赋值
#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
//定义结构体类型时不要直接给成员赋值
//结构体只是一个类型,还没有分配空间
//只有根据其类型定义变量时,才分配空间,有空间后才能赋值
typedef struct Teacher
{
char name[50];
int age;
}Teacher;
void copyTeacher(Teacher *to, Teacher *from)
{
*to = *from;
}
int main(void)
{
Teacher t1 = { "lily",22 };
//相同类型的两个结构体变量,可以相互赋值
//把t1成员变量内存的值拷贝给t2成员变量的内存
//t1与t2没有关系
Teacher t2 = t1;
printf("%s ,%d\n", t2.name, t2.age);
Teacher t3;
memset(&t3, 0, sizeof(t3));
copyTeacher(&t3, &t1);
printf("%s ,%d\n", t3.name, t3.age);
printf("\n");
system("pause");
return 0;
}
结构体动态数组
#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
typedef struct Teacher
{
char name[50];
int age;
}Teacher;
int main(void)
{
Teacher a[3] = {
{"a",18},
{"b",19},
{"c",20}
};
//静态
Teacher a2[3] = { "a",18,"b",19,"c",20 };
int i = 0;
for (i = 0; i++; i < 3)
{
printf("%s ,%d\n", a2[i].name, a2[i].age);
}
//动态
Teacher *p = (Teacher *)malloc(3 * sizeof(Teacher));
char buf[50];
for (i = 0; i < 3;i++ )
{
sprintf(buf, "name%d%d%d",i,i,i);
strcpy(p[i].name, buf);
p[i].age = 20 + i;
}
for (i = 0; i < 3; i++)
{
printf("%s ,%d\n", p[i].name, p[i].age);
}
if(p != NULL)
{
free(p);
p = NULL;
}
printf("\n");
system("pause");
return 0;
}
结构体嵌套一级指针
#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
typedef struct Teacher
{
char *name;
int age;
}Teacher;
int main(void)
{
/*
char *name = NULL;
name = (char *)malloc(30);
strcpy(name,"lily");
printf("name = %s\n", name);
if (name != NULL)
{
free(name);
name = NULL;
}
*/
//1
Teacher t;
t.name = (char *)malloc(30);
strcpy(t.name, "lily");
t.age = 20;
printf("name = %s ,age = %d\n", t.name, t.age);
if (t.name != NULL)
{
free(t.name);
t.name = NULL;
}
//2
Teacher *p = NULL;
p = (Teacher *)malloc(sizeof(Teacher));
p->name = (char *)malloc(30);
strcpy(p->name, "lihua");
p->age = 22;
printf("name = %s ,age = %d\n", p->name, p->age);
if (p->name != NULL)
{
free(p->name);
p->name = NULL;
}
if (p != NULL)
{
free(p);
p = NULL;
}
//3
Teacher *q = NULL;
q= (Teacher *)malloc(sizeof(Teacher) * 3);
//Teacher q[3]
int i = 0;
char buf[30];
for(i = 0; i < 3; i++)
{
q[i].name = (char *)malloc(30);
sprintf(buf, "name%d%d", i, i);
strcpy(q[i].name, buf);
q[i].age = 20 + i;
}
for (i = 0; i < 3; i++)
{
printf("name = %s ,age = %d\n", q[i].name, q[i].age);
}
for (i = 0; i < 3; i++)
{
if (q[i].name != NULL)
{
free(q[i].name);
q[i].name = NULL;
}
}
if (q != NULL)
{
free(q);
q = NULL;
}
printf("\n");
system("pause");
return 0;
}
代码封装
#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
typedef struct Teacher
{
char *name;
int age;
}Teacher;
void showTeacher(Teacher *p,int n)
{
int i = 0;
for (i = 0; i < n; i++)
{
printf("name = %s ,age = %d\n", p[i].name, p[i].age);
}
}
void freeTeacher(Teacher *p, int n)
{
int i = 0;
for (i = 0; i < n; i++)
{
if (p[i].name != NULL)
{
free(p[i].name);
p[i].name = NULL;
}
}
if (p != NULL)
{
free(p);
p = NULL;
}
}
Teacher *getMem(int n)
{
Teacher *p = (Teacher *)malloc(sizeof(Teacher) * 3);
//Teacher p[3]
int i = 0;
char buf[30];
for (i = 0; i < n; i++)
{
p[i].name = (char *)malloc(30);
sprintf(buf, "name%d%d", i, i);
strcpy(p[i].name, buf);
p[i].age = 20 + i;
}
return p;
}
int getMem2(Teacher **tmp, int n)
{
if (tmp == NULL)
{
return - 1;
}
Teacher *p = (Teacher *)malloc(sizeof(Teacher) * 3);
//Teacher p[3]
int i = 0;
char buf[30];
for (i = 0; i < n; i++)
{
p[i].name = (char *)malloc(30);
sprintf(buf, "name%d%d", i, i);
strcpy(p[i].name, buf);
p[i].age = 20 + i;
}
*tmp = p;
return 0;
}
int main(void)
{
/*
char *name = NULL;
name = (char *)malloc(30);
strcpy(name,"lily");
printf("name = %s\n", name);
if (name != NULL)
{
free(name);
name = NULL;
}
*/
//1
Teacher t;
t.name = (char *)malloc(30);
strcpy(t.name, "lily");
t.age = 20;
printf("name = %s ,age = %d\n", t.name, t.age);
if (t.name != NULL)
{
free(t.name);
t.name = NULL;
}
//2
Teacher *p = NULL;
p = (Teacher *)malloc(sizeof(Teacher));
p->name = (char *)malloc(30);
strcpy(p->name, "lihua");
p->age = 22;
printf("name = %s ,age = %d\n", p->name, p->age);
if (p->name != NULL)
{
free(p->name);
p->name = NULL;
}
if (p != NULL)
{
free(p);
p = NULL;
}
//3
Teacher *q = NULL;
//q = getMem(3);//实现1
//实现2
int ret = 0;
ret = getMem2(&q,3);
if (ret != 0)
{
return ret;
}
showTeacher(q,3);
freeTeacher(q, 3);
q = NULL;
printf("\n");
system("pause");
return 0;
}
结构体套二级指针
#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
typedef struct Teacher
{
char **stu;//二维内存
}Teacher;
int main(void)
{
char **name = NULL;
//char *name[3];
int n = 3;
int i = 0;
int j = 0;
name = (char **)malloc(n * sizeof(char *));
//char buf[30]
for (i = 0; i < n; i++)
{
name[i] = (char *)malloc(30);
strcpy(name[i], "lily");
}
for (i = 0; i < n; i++)
{
printf("%s\n", name[i]);
}
for (i = 0; i < n; i++)
{
if (name[i] != NULL)
{
free(name[i]);
name[i] = NULL;
}
}
if (name != NULL)
{
free(name);
name = NULL;
}
//1
Teacher t;
//t.stu[3]
//char *t.stu[3];
t.stu = (char **)malloc(n * sizeof(char *));
//char buf[30]
for (i = 0; i < n; i++)
{
t.stu[i] = (char *)malloc(30);
strcpy(t.stu[i], "lihe");
}
for (i = 0; i < n; i++)
{
printf("%s\n", t.stu[i]);
}
for (i = 0; i < n; i++)
{
if (t.stu[i] != NULL)
{
free(t.stu[i]);
t.stu[i] = NULL;
}
}
if (t.stu != NULL)
{
free(t.stu);
t.stu = NULL;
}
//2
Teacher *p = NULL;
//p->stu[3]
p = (Teacher *)malloc(sizeof(Teacher));
//char p->stu[3];
p->stu = (char **)malloc(n * sizeof(char *));
//char buf[30]
for (i = 0; i < n; i++)
{
p->stu[i] = (char *)malloc(30);
strcpy(p->stu[i], "lihua");
}
for (i = 0; i < n; i++)
{
printf("%s\n", p->stu[i]);
}
for (i = 0; i < n; i++)
{
if (p->stu[i] != NULL)
{
free(p->stu[i]);
p->stu[i] = NULL;
}
}
if (p->stu != NULL)
{
free(p->stu);
p->stu = NULL;
}
if (p != NULL)
{
free(p);
p = NULL;
}
//3
Teacher *q = NULL;
//Teacher q[3]
//q[i].stu[3]
q = (Teacher *)malloc(sizeof(Teacher) * 3);
for (i = 0; i < n; i++)
{
q[i].stu= (char **)malloc(n * sizeof(char *));//char *stu[3]
for (j = 0; j < 3; j++)
{
q[i].stu[j] = (char *)malloc(30);//char buf[30]
char buf[30];
sprintf(buf, "name%d%d%d%d", i, i, j, j);
strcpy(q[i].stu[j], buf);
}
}
for (i = 0; i < 3; i++)
{
printf("%s, %s, %s\n", q[i].stu[0], q[i].stu[1], q[i].stu[2]);
}
for (i = 0; i < 3; i++)
{
for (j = 0; j < 3; j++)
{
if (q[i].stu[j] != NULL)
{
free(q[i].stu[j]);
q[i].stu[j] = NULL;
}
}
if (q[i].stu != NULL)
{
free(q[i].stu);
q[i].stu = NULL;
}
}
if (q != NULL)
{
free(q);
q = NULL;
}
printf("\n");
system("pause");
return 0;
}
封装函数后代码如下
#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
typedef struct Teacher
{
char **stu;//二维内存
}Teacher;
int creatTeacher(Teacher **tmp,int n1,int n2)//n1老师个数,n2老师带学生个数
{
int i = 0;
int j = 0;
if (tmp == NULL)
{
return - 1;
}
Teacher *q = (Teacher *)malloc(sizeof(Teacher) * n1);
for (i = 0; i < n1; i++)
{
q[i].stu = (char **)malloc(n2 * sizeof(char *));//char *stu[3]
for (j = 0; j < n2; j++)
{
q[i].stu[j] = (char *)malloc(30);//char buf[30]
char buf[30];
sprintf(buf, "name%d%d%d%d", i, i, j, j);
strcpy(q[i].stu[j], buf);
}
}
//间接赋值是指针的最大意义
*tmp = q;
return 0;
}
void showTeacher(Teacher *q, int n1, int n2)
{
int i = 0;
int j = 0;
if (q == NULL)
{
return;
}
for (i = 0; i < n1; i++)
{
for (j = 0; j < n2; j++)
{
printf("%s,", q[i].stu[j]);
}
printf("\n");
}
}
void freeTeacher(Teacher **tmp, int n1, int n2)
{
if (tmp == NULL)
{
return;
}
Teacher *q = *tmp;
int i = 0;
int j = 0;
for (i = 0; i < n1; i++)
{
for (j = 0; j < n2; j++)
{
if (q[i].stu[j] != NULL)
{
free(q[i].stu[j]);
q[i].stu[j] = NULL;
}
}
if (q[i].stu != NULL)
{
free(q[i].stu);
q[i].stu = NULL;
}
}
if (q != NULL)
{
free(q);
q = NULL;
*tmp = NULL;
}
}
int main(void)
{
Teacher *q = NULL;
int ret = 0;
ret = creatTeacher(&q, 3, 3);
if (ret != 0)
{
return ret;
}
//Teacher q[3]
//q[i].stu[3]
showTeacher(q, 3, 3);
freeTeacher(&q, 3, 3);
printf("\n");
system("pause");
return 0;
}
结构体深拷贝与浅拷贝
结构体中嵌套指针,而且动态分配空间,同类型结构体变量赋值,会导致浅拷贝。结构体成员指针变量指向同一块内存
#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
typedef struct Teacher
{
char *name;
int age;
}Teacher;
int main(void)
{
Teacher t1;
t1.name = (char *)malloc(30);
strcpy(t1.name, "lily");
t1.age = 23;
Teacher t2;
t2 = t1;//浅拷贝,t1.name与t2.name指向同一块内存区域
printf("[t2]%s, %d\n", t2.name, t2.age);
/*
if (t2.name != NULL)//再释放一次程序就会崩
{
free(t1.name);
t1.name = NULL;
}
*/
//深拷贝,重新拷贝一下
Teacher t3;
t3 = t1;
t3.name = (char *)malloc(30);
strcpy(t3.name, t1.name);
//t3.age = t1.age;
printf("[t3]%s, %d\n", t3.name, t3.age);
if (t1.name != NULL)//释放一次即可
{
free(t1.name);
t1.name = NULL;
}
if (t3.name != NULL)//
{
free(t1.name);
t3.name = NULL;
}
printf("\n");
system("pause");
return 0;
}
结构体对齐规则
结构体中所有成员的对齐参数N的最大值称为结构体的对齐参数。
如果结构体中嵌套结构体,如结构体A中嵌套结构体B,则先看A中基本成员的的参数最大值,再看B中基本成员参数最大值,以最大的为对齐参数。
struct
{
int a;
short b;
}A;//占8个字节
//对齐单位为4字节
/*
偏移量:
a:4*0=0
b:2*2=4
struct
{
double a;
int b;
short c;
}B;//占16 个字节
//对齐单位为8字节
/*
偏移量
a:8*0=0
b:4*2=8
c:2*6=12
struct
{
int a;
double b;
short c;
}B;//占24 个字节
//对齐单位为8字节
/*
偏移量
a:4*0=0
b:8*1=8
c:2*8=16
//嵌套结构体
struct A
{
int a;
double b;
float c;
};//占24 个字
struct
{
char e[2];
int f;
double g;
short h;
struct A i;
}B;//占48字节
//对齐单位为8
/*
偏移量
e:2*0=0;
f:4*1=4;
g:8*1=8;
h:2*8=16;
//注意结构体的起点位置,就算h为占满8字节,由于新的结构体成员,所以直接*填满
结构体i起点坐标:
8*3=24
a:24+4*0=24;
b:24+8*1=28;
c:24+4*4=40;
#pragma pack(2)//指定对其单位为2
//若为#pragma pack(8),超过了结构体中最长的成员,则以最长成员对齐即为4
typedef struct
{
int a;
char b;
short c;
char d;
}A;//占10字节
/*
偏移量
a:2*0=0;
b:1*4=4;
c:2*3=6;
d:1*4=8;
结构体嵌套结构体
1、结构体可以嵌套另外一个结构体的任何类型变量
2、结构体嵌套本结构体变量(不可以),因为本结构体类型大小无法确定;类型本质:固定大小内存别名
3、结构体嵌套本结构体指针变量(可以),指针变量的内存空间可以确定。
typedef struct A
{
int a;
int b;
char *p
}A;
typedef struct B
{
int c;
A tmp1;//ok
A *p1;//ok
struct B tmp2;//err
struct B*next;//ok
}B;
链表:每一个节点即一个结构体
数组与链表对比:
数组:一次性分配一块连续地存储区域
优点:随机访问元素效率高
缺点:需要分配一块连续地存储区域(很大区域,有可能分配失败);删除和插入某个元素效率低
链表:
优点:不需要一块连续地存储区域;删除和插入某个元素效率高
缺点:随机访问元素效率低
概念:
节点:数据域,指针域
结尾点:指针域指向NULL
静态链表:
#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
typedef struct Stu
{
int id;//数据域
char name[100];
struct Stu *next;//指针域
}Stu;
int main(void)
{
//初始化三个结构体变量
Stu s1 = { 1,"tom",NULL };
Stu s2 = { 2,"tina",NULL };
Stu s3 = { 3,"lisa",NULL };
//形成链表
s1.next = &s2;
s2.next = &s3;
s3.next = NULL;//尾结点
Stu *p = &s1;
while (p != NULL)
{
printf("id = %d,name = %s\n", p->id, p->name);
//节点往后移动一位
p = p->next;
}
printf("\n");
system("pause");
return 0;
}
链表操作:头结点的创建和链表的遍历,节点的插入,清空链表
#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
typedef struct Node
{
int id;
struct Node *next;
}Node;
//创建头节点
Node *SListCreat()
{
Node *head = NULL;
//头节点作为标志,不存属有效数据
head = (Node *)malloc(sizeof(Node));
if(head==NULL)
{
return NULL;
}
//给head的成员赋值
head->id = -1;
head->next = NULL;
Node *pCur = head;
Node *pNew = NULL;
int data;
while (1)
{
printf("请输入数据:");
scanf("%d", &data);
if (data == -1)
{
break;
}
//新节点动态分配空间
pNew = (Node *)malloc(sizeof(Node));
if (pNew == NULL)
{
continue;
}
pNew->id = data;
pNew->next = NULL;
//链表建立关系
pCur->next = pNew;
//pNew下一个节点指向NULL
pNew->next = NULL;
//把pCur移动到pNew
pCur = pNew;
}
return head;
}
//链表的遍历
int SListPrint(Node *head)
{
if (head == NULL)
{
return - 1;
}
//取出第一个有效节点(头节点的next)
Node *pCur = head->next;
printf("head-> ");
while (pCur != NULL)
{
printf("%d->", pCur->id);
pCur = pCur->next;
}
printf("NULL\n");
return 0;
}
//插入节点,在值为x的节点前插入值为y的节点;若值为x的节点不存在,则插在表尾
int SListNodeInsret(Node *head,int x,int y)
{
if (head == NULL)
{
return -1;
}
Node *pPre = head;
Node *pCur = head->next;
while (pCur != NULL)
{
if (pCur->id == x)//找到匹配节点
{
break;
}
pPre = pCur;
pCur = pCur->next;
}
//2种情况
//1.找到匹配的节点,pCur为匹配节点
//2.没有找到匹配节点,pCur为空节点,pPre为最后一个节点
//给新的节点动态分配空间
Node *pNew = (Node *)malloc(sizeof(Node));
if (pNew == NULL)
{
return -2;
}
//给pNew的成员变量赋值
pNew->id = y;
pNew->next = NULL;
pPre->next = pNew;
pNew->next = pCur;
return 0;
}
//删除第一个值为x的节点
int SListNodeDel(Node *head, int x)
{
if (head == NULL)
{
return -1;
}
Node *pPre = head;
Node *pCur = head->next;
int flag = 0;//0代表没有找到
while (pCur != NULL)
{
if (pCur->id == x)//找到匹配节点
{
pPre->next = pCur->next;
free(pCur);
pCur = NULL;
flag = 1;
break;
}
pPre = pCur;
pCur = pCur->next;
}
if (0 == flag)
{
printf("没有值为%d的节点\n", x);
return -2;
}
return 0;
}
//清空链表,释放所有节点
int SListNodeDestroy(Node *head)
{
if (head == NULL)
{
return -1;
}
Node *tmp = NULL;
int i = 0;
while (head != NULL)
{
tmp = head->next;
free(head);
head = NULL;
head = tmp;
i++;
}
printf("释放次数:%d的\n", i);
return 0;
}
int main(void)
{
Node *head = NULL;
head = SListCreat();//创建头节点
SListPrint(head);
//在5的前面插入4
SListNodeInsret(head, 5, 4);
SListPrint(head);
SListNodeDel(head, 5);
SListPrint(head);
SListNodeDestroy(head);
head = NULL;
printf("\n");
system("pause");
return 0;
}
函数指针
#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
//指针函数,()的优先级比*高,它是函数,返回值是指针类型
//返回指针类型的函数
int *fun2()
{
int *p = (int *)malloc(sizeof(int));
return p;
}
int fun(int a)
{
printf("a=%d\n", a);
return 0;
}
int main(void)
{
//函数指针,它是指针,指向函数的指针
//定义函数指针有3种形式
//1、先定义函数类型,根据函数类型定义指针变量(不常用)
//有typedef是类型,没有是变量
typedef int FUN(int a);//FUN函数类型
FUN *p1 = NULL;
p1 = fun;//p1指向fun函数
fun(5);//传统调用
p1(6);//指针变量调用方式
//2、先定义函数指针类型,根据类型定义指针变量(常用)
typedef int (*PFUN)(int a);//PFUN,函数指针类类型
PFUN p2 = fun;//p2指向fun函数
p2(7);
//3、直接定义函数指针(常用)
int(*p3)(int a) = fun;
p3(8);
printf("\n");
system("pause");
return 0;
}
函数指针应用:函数指针数组
#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
void add()
{
printf("addfunction\n");
}
void minus()
{
printf("minusfunction\n");
}
void multi()
{
printf("multifunction\n");
}
void divide()
{
printf("dividefunction\n");
}
void myexit()
{
exit(0);
}
int main(void)
{
#if 0
char cmd[100];
while (1)
{
printf("请输入指令: ");
scanf("%s", cmd);
if (strcmp(cmd, "add") == 0)
{
add();
}
else if (strcmp(cmd, "min") == 0)
{
minus();
}
else if (strcmp(cmd, "mul") == 0)
{
multi();
}
else if (strcmp(cmd, "div") == 0)
{
divide();
}
else if (strcmp(cmd, "exit") == 0)
{
myexit();
}
}
#endif
void(*fun1)() = add;
fun1();
//函数指针数组
void(*fun[5])() = { add,minus,multi,divide,myexit };
//指针数组
char *buf[] = { "add","min","mul","div","exit" };
int i = 0;
char cmd[100];
while (1)
{
printf("请输入指令: ");
scanf("%s", cmd);
for (i = 0; i < 5; i++)
{
if (strcmp(cmd, buf[i]) == 0)
{
fun[i]();
break;//跳出for循环
}
}
}
printf("\n");
system("pause");
return 0;
}
函数指针应用:回调函数(函数指针做函数参数)
你到一个商店买东西,刚好你要的东西没有货,于是你在店员那里留下了你的电话,过了几天店里有货了,店员就打了你的电话,然后你接到电话后就到店里去取了货。在这个例子里,你的电话号码就叫回调函数,你把电话留给店员就叫登记回调函数,店里后来有货了叫做触发了回调关联的事件,店员给你打电话叫做调用回调函数,你到店里去取货叫做响应回调事件。回答完毕。
当函数指针 做为函数的参数,传递给一个被调用函数,被调用函数就可以通过这个指针调用外部的函数,这就形成了回调。
#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
void add(int a,int b)
{
return (a + b);
}
void minus(int a, int b)
{
return (a - b);
}
void multi(int a, int b)
{
return (a * b);
}
void divide(int a, int b)
{
return (a / b);
}
void myexit()
{
exit(0);
}
//框架,固定不变
//多态,调用同一接口,不一样的结果
void fun(int x, int y,int (*p)(int a,int b))
{
printf("fun\n");
int a = p(x, y);//回调函数
printf("a = %d\n", a);
}
//方法2
typedef int(*Q)(int a, int b);
void fun2(int x, int y, Q p)
{
printf("fun\n");
int a = p(x, y);//回调函数
printf("a = %d\n", a);
}
int main(void)
{
fun(1, 2, add);
fun(10, 5, minus);
fun(10, 5, divide);
printf("\n");
system("pause");
return 0;
}
例子:
#include <iostream>
using namespace std;
typedef void(*PF)();
PF g_pf = NULL;
/******************B模块****************/
// B模块向外提供的回调函数注册接口,也就是说,提供注册服务,想注册的,调用该接口即可
void registerFun(PF pf)
{
g_pf = pf;
}
// B模块的某函数,在一定条件下被触发
void fun()
{
// 执行别的模块注册过来的回调函数
(*g_pf)(); // or g_pf();
}
/*****************A模块*****************/
// A模块的回调函数
void callBack()
{
cout << "call back function" << endl;
}
// A 模块的主函数
int main()
{
// A模块利用B模块的注册接口, 向B模块注册
registerFun(callBack);
// 在一定条件下,B模块的fun函数被触发了
fun();
return 0;
}
#define _CRT_SECURE_NO_WARNINGS
#include <iostream>
using namespace std;
// 定义一个锦囊的方法 是一个函数指针,类似于c++的纯虚函数
typedef void(TIPS_FUNC)(void);
//写一个锦囊的结构体
struct tips
{
char from[64]; //这个锦囊是谁写的
char to[64]; //写给谁的
TIPS_FUNC *fp; //具体锦囊的内容
};
//写一个供赵云调用的架构函数
void open_tips(struct tips * tp)
{
cout << "打开了锦囊" << endl;
cout << "此锦囊是由" << tp->from << ", 写给" << tp->to << endl;
cout << "内容是" << endl;
tp->fp();//拆开锦囊,调用具体锦囊的方法
}
//实现一个一个的锦囊 //类似于实现一个纯虚函数
void tips_1(void)
{
cout << "一到东吴就大张旗鼓找乔国老" << endl;
}
void tips_2(void)
{
cout << "骗刘备 操作压境" << endl;
}
void tips_3(void)
{
cout << "找孙尚香求救" << endl;
}
void tips_4(void)
{
cout << "你们就死在东吴把" << endl;
}
struct tips* create_tips(char *from, char *to, TIPS_FUNC *fp)
{
struct tips *tp = (struct tips*)malloc(sizeof(struct tips));
if (tp == NULL) {
return NULL;
}
strcpy(tp->from, from);
strcpy(tp->to, to);
//注册回调函数
tp->fp = fp; //给拥有函数指针的结构体 函数指针变量 赋值 就是 注册回调函数
return tp;
}
void destory_tips(struct tips * tp)
{
if (tp != NULL) {
free(tp);
}
}
int main(void)
{
//诸葛亮去写锦囊
struct tips * tp1 = create_tips("孔明", "赵云", tips_1);
struct tips * tp2 = create_tips("孔明", "赵云", tips_2);
struct tips * tp3 = create_tips("孔明", "赵云", tips_3);
struct tips * tp4 = create_tips("庞统", "赵云", tips_4);
// 赵云去拆机囊
cout << "刚来到 东吴境内 ,打开了第一个锦囊" << endl;
open_tips(tp1);
cout << "刘备乐不思蜀 ,打开第二个锦囊 " << endl;
open_tips(tp2);
cout << "孙权追杀刘备, 打开第三个锦囊" << endl;
open_tips(tp3);
cout << "赵云发现 抵挡不住 军队,想到了庞统的最后一个锦囊 打开了" << endl;
open_tips(tp4);
destory_tips(tp1);
destory_tips(tp2);
destory_tips(tp3);
destory_tips(tp4);
return 0;
}
回调函数的优点:
①函数的调用和函数的实现 有效地分离
②类似C++中的多态,可扩展
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)