1接口的封装和设计思想入门

接口的封装和设计思想入门

第一套api函数

#ifndef _CLT_SOCKET_H__

#define _CLT_SOCKET_H__

//客户端初始化环境

int cltSocket_init(void **handle); //5day

//客户端发报文

int cltSocket_senddata(void *handle, unsigned char *buf, int buflen);

//客户端收报文

int cltSocket_resvdata(void *hanle , unsigned char *buf, int *buflen);

//4 客户端销毁环境

int cltSocket_destory(void *handle);

#endif

第二套api函数

//第二套api函数

#ifndef _CLT_SOCKET_H__

#define _CLT_SOCKET_H__

//客户端初始化环境

int cltSocket_init2(void **handle); //5day

//客户端发报文

int cltSocket_senddata2(void *handle, unsigned char *buf, int buflen);

//客户端收报文

int cltSocket_resvdata2(void *hanle , unsigned char **buf, int *buflen);

//为什么这个地方换成了一个二级指针,而且又增加了一个接口 4day

int cltSocket_resvdata_Free2(unsigned char *buf);

//4 客户端销毁环境

//为什么这个地方又加了一个* 4day

int cltSocket_destory2(void **handle);

#endif

我们找到了一套标准,我们可以高效的学习,更重要的是,我们能务实的,集中话题学习这套api函数

Socket动态库业务模型思路分析

 

3学习标准热身

排序

选择法排序思想总结

 

核心排序代码

printfArray3(a);

for(i=0; i<10; i++)

{

for (j=i+1;j<10; j++)

{

if (a[i] < a[j])

{

tmp = a[i];

a[i] = a[j];

a[j] = tmp;

}

}

}

printf("\n排?序¨°之?后¨®:");

结论

//1数组做函数参数,会退化为指针

//2在形参里面出现的char buf[30] int a[10] c/c++编译器会把它当做指针,也不会主动的多分配内存,c、c++编译器会自动优化

// int i = 0;

int num1 = sizeof(a);

int num2 = sizeof(*a);

int num = sizeof(a)/sizeof(*a);

int num1 = sizeof(a); //数据类型不一样

//3 sizeof(a)大小不一样的实质是a的数据类型不一样

4数据类型本质剖析

数据类型问题抛出

压死初学者的三座大山

1、数组类型

2、数组指针

3、数组类型和数组指针的关系

void main()

{

int a[10] = {1, 3, 44, 2, 3, 44, 5, 5,6, 67};

printf(“a:%d &a:%d \n”, a, &a); //a &a大小一样

printf(“a+1:%d &a+1:%d \n”, a+1, &a +1 ); //+1 大小不一样

//a &a数据类型不一样 步长不一样

//压死出血

system(“pause”);

}

数据类型分为两种,简单、一个复杂,思考复杂数据类型的时候,不能用简单数据类型思考之。。。。。抛砖

//写一个函数 把内存地址给传出被调用函数,方法有2种

结论:

数据类型本质:固定大小内存的别名

数据类型取别名 typdedef 抛出问题:

如何表达:int array[10]   int add(int a, int d);//15

5变量的本质

修改变量的方法

两种+引用

变量的本质:连续内存块的别名,变量是一个标号。再抛砖

程序的内存四区图,画变量示意图时,主要把变量放在外面,内存空间留出来

内存空间可以再取给别名吗?

6内存四区概念

基本概念

函数1调用函数2,函数1称为主调函数 函数2称为被调用函数

规则1:Main(主调函数)分配的内存(在堆区,栈区、全局区)都可以在被调用函数里使用吧。

规则2:在被调用函数里面分配的内存

1、如果在被调用函数里面的临时区(栈)分配内存,主调用函数是不能使用的。

char * getstring3()

{

char buf[30];

strcpy(buf, "abcde");

return buf;

}

 
 

铁律1

铁律1:指针是一种数据类型  

1) 指针也是一种变量,占有内存空间,用来保存内存地址

测试指针变量占有内存空间大小

2)*p操作内存

在指针声明时,*号表示所声明的变量为指针

在指针使用时,*号表示 操作 指针所指向的内存空间中的值

*p相当于通过地址(p变量的值)找到一块内存;然后操作内存

*p放在等号的左边赋值(给内存赋值)

*p放在等号的右边取值(从内存获取值)

3)指针变量和它指向的内存块是两个不同的概念

//含义1 给p赋值p=0x1111; 只会改变指针变量值,不会改变所指的内容;p = p +1; //p++

//含义2 给*p赋值*p='a'; 不会改变指针变量的值,只会改变所指的内存块的值

//含义3 =左边*p 表示 给内存赋值, =右边*p 表示取值 含义不同切结!

//含义4 =左边char *p

//含义5 保证所指的内存块能修改

4)指针是一种数据类型,是指它指向的内存空间的数据类型

含义1:指针步长(p++),根据所致内存空间的数据类型来确定

p++=è(unsigned char )p+sizeof(a);

结论:指针的步长,根据所指内存空间类型来定。

 
 

不断地修改指针变量的值含义场景建立

//不断地修改指针变量的值含义

//需要建立场景,解决指针乱指问题

void main()

{

int i = 10;

char buf[20];

char *p = NULL;

strcpy(buf, "a234567899987654");

p = &buf[0];

p = &buf[1];

p = &buf[2];

p = &buf[3];

p = &buf[4];

for (i=0; i<10; i++)

{

p = &buf[i];

}

}

2经验话语

#ifndef _CLT_SOCKET2_H__

#define _CLT_SOCKET2_H__

#endif

// 避免在.c里面 重复包含多次头文件

#include "cltsocket.h"

#include "cltsocket.h"

#include "cltsocket.h"

Shift+del建组合删除一行

Ctlr+u 让单词从小写变大写

Shift+ctrl+u 从大小变小写

//避免多次重复包含 整个思路分析

C语言中的灰色地带这种问题,往后放

 

有关字面量

有关字面量的理解

{

//10 字面量  放在不能取地址 没有放在堆栈、全局区,可以按照放在代码区之类的区域内理解它。

int *a = &10;

}

怎么样理解(多级)指针做函数参数,

//对参数的指针类型应该怎么理解

//理解角度需要从两个角度出发

//第一个角度:站在c/c++编译器的角度 对形参,如果是指针类型,c编译器只会把它当作一个指针变量来看。(配四个自己的内存)。

////char *p7 形参 是变量

//第二个角度:我们只有在使用指针所指向的内存空间的时候,我们才去关心内存是一维的,还是二维的。

/*

void senddata01(char    *p1); void senddata01(char*            p1);

void senddata02(char **    p1); void senddata02(char *     *p1);  void senddata02(char         **p1);

void senddata03(char ***p1);

void senddata04(char *p[]); void senddata04(char *     p[]);  void senddata04(char *p    []);

void senddata05(char (*p)[10]); void senddata05(char (*p)             [10]);

void senddata05(char *****p4);

*/

内存块数据打包

//(unsigned char *buf +len)内存块的数据打包

有关[] *

//buf[i]-->buf[0+i];--->*(p+i)  ---> p[i]

//站在c++编译器的角度, *p 相当于我们程序员手工(显示)利用间接赋值,去操作内存

//[]怎么理解,只不过是c++编译器帮我们程序员做了一个*p的操作

char buf[100] = "abcdefg";

char *p = NULL;

for (i=0; i<strlen(buf); i++)

{

printf(" %c", p[i]);

}

printf("\n");

for (i=0; i<strlen(buf); i++)

{

printf(" %c", *(p+i));

}


间接赋值成立的是三个条件

间接赋值成立的是三个条件

/* 间接赋值成立的三个条件

条件1:定义了一个变量(实参)定义了一个变量(形参)

条件2:建立关联,//实参取地址传给形参

条件3://*p形参,去间接的修改实参的值

main --->func

*/

//间接赋值成立的三个条件,应用起来。。。。

//123 写在一个函数里面,那么成了第一个应用场景

//12    3 //间接赋值是指针存在的最大意义

//1      23  //抛砖,,,,到时候,要认识啊。

//间接赋值的应用场景有2个

//场景1:在函数指针  *p1++ = *p2++

//场景2:指针做函数参数,通过*p形参求间接的修改实参的值,这才是指针存在的最大意义、。

//这才是C语言特有的现象,才是指针的精华

//*p间接赋值是指针存在的最大意义(现实意义)

接口的封装和设计

//函数调用时,形参传给实参,用实参取地址,传给形参,在被调用函数里面用*p,

//来改变实参,把运算结果传出来。

//指针作为函数参数的精髓。

推论

//指针做函数参数

//函数调用过程中,

//用1级指针(通常是形参,)去修改0级指针(通常是实参)的值

//用2级指针(通常是形参,)去修改1级指针(通常是实参)的值

//用3级指针(通常是形参,)去修改2级指针(通常是实参)的值

//用8级指针(通常是形参,)去修改7级指针(通常是实参)的值

//用n级指针(通常是形参,)去修改n-1级指针(通常是实参)的值

/*

整个C/C++领域值得我们做技术推演的领域

0--1

1->2 2->3

c++多态(函数指针做函数参数)

Aop切面编程(2-3)

*/

03字符串专题讲座

内存模型

//1在c中没有字符串这种类型,是通过字符串数组(char buf[100])去模拟

//2 字符串和字符串数组的区别 是不是 带有\0

//print函数是c库函数,它就是按照C风格字符串进行输出数据

//通过字符串常量初始化字符串数组

//通过这种方法它会自动给你\0

char buf4[] = "abcdefg";

printf("%s\n", buf4);

//

//strlen() 是一个函数 求字符串的长度(不是求字符数组的长度),它的长度不包括\0

//sizeof() 是一个操作符,求数据类型(实体)的大小

int main13()

{

char buf[20]="aaaa";

int a = 10; //字面量

char buf2[] = "bbbb";

//char ***********************************************p1 = "111111";

char *p1 = "111111";

char *p2 = malloc(100);

strcpy(p2, "3333");

//&a; //&a表达式 表达式的运算结果放在寄存器里

}

 

//buf[i]-->buf[0+i];--->*(p+i)  ---> p[i]

//站在c++编译器的角度, *p 相当于我们程序员手工(显示)利用间接赋值,去操作内存

//[]怎么理解,只不过是c++编译器帮我们程序员做了一个*p的操作

//因为后缀++的优先级,高于,*p;

void copy_str4(char *from , char *to)

{

while((*to ++ = *from++) != '\0')

{

;

}

}

重要概念概念

在C语言中使用字符数组来模拟字符串

C语言中的字符串是以’\0’结束的字符数组

C语言中的字符串可以分配于栈空间,堆空间或者只读存储区

03 字符串操作

数组法,下标法

字符数组名,是个指针,是个常量指针;

字符数组名,代表字符数组首元素的地址,不代表整个数组的。

如果代表这个数组,那需要数组数据类型的知识!

字符串做函数参数

void copy_str01(char *from, char *to)

{

for (; *from!='\0'; from++, to++)

{

*to = *from;

}

*to = '\0';

}

void copy_str02(char *from, char *to)

{

while(*from!='\0')

{

*to++ = *from++;

}

*to = '\0';

}

void copy_str03(char *from, char *to)

{

while( (*to=*from) !='\0')

{

to++;

from++;

}

}

void copy_str04(char *from, char *to)

{

while( (*to++=*from++) !='\0')

{

;

}

}

int copy_str05_good(const char *from, char *to)

{

if (from==NULL || to==NULL)

{

printf("func copy_str05_good() err. (from==NULL || to==NULL)\n");

return -1;

}

while( (*to++=*from++) !='\0')

{

;

}

return 0;

}

字符串操作典型错误

建立一个思想:是主调函数分配内存,还是被调用函数分配内存;

越界 语法级别的越界

char buf[3] = "abc";

越界

越界 语法级别的越界

char buf[3] = "abc";

不断修改内存指针变量

越界

 

void copy_str_err(char *from, char *to)

{

char *fromtmp = from;

for (; *from!='\0'; from++, to++)

{

*to = *from;

}

*to = '\0';

printf("to:%s", to);

printf("from:%s", from);

}

4、你向外面传递什么

1、临时str3内存空间

// char *str_cnct(x,y)     /*简化算法*/

// char *x,*y;

char *str_cnct(char *x, char* y)     /*简化算法*/

{

char str3[80];

char *z=str3; /*指针z指向数组str3*/

while(*z++=*x++);

z--;                /*去掉串尾结束标志*/

while(*z++=*y++);

z=str3;  /*将str3地址赋给指针变量z*/

return(z);

}

2、经验要学习

while(*z++=*x++);

z--;                /*去掉串尾结束标志*/

char *str_cnct(char *x, char* y)     /*简化算法*/

{

char * str3= (char *)malloc(80)

char *z=str3; /*指针z指向数组str3*/

while(*z++=*x++);

z--;                /*去掉串尾结束标志*/

while(*z++=*y++);

z=str3;  /*将str3地址赋给指针变量z*/

return(z);

}

char *str_cnct(char *x, char* y)     /*简化算法*/

{

If (x == NULL)

{

Return NULL;

}

char * str3= (char *)malloc(80)

char *z=str3; /*指针z指向数组str3*/

while(*z++=*x++);

z--;                /*去掉串尾结束标志*/

while(*z++=*y++);

z=str3;  /*将str3地址赋给指针变量z*/ note:

return(z);

}

Main ()

{

Char *p = str_cnct(“abcd”, “ddeee”);

If (p != NULL) {Free(p) ;p = NULL}//yezhizhen

}

int getKeyByValude(char *keyvaluebuf,  char *keybuf,  char *valuebuf, int * valuebuflen)

{

int result = 0;

char *getbuf = new char[100];

memset(getbuf, 0, sizeof(getbuf));

char *trimbuf = new char[100];

memset(trimbuf, 0, sizeof(trimbuf));

int destlen = strlen(keyvaluebuf);

if (keybuf == NULL || keyvaluebuf == NULL || valuebuf == NULL/* || valuebuflen == NULL*/)

{

result = -1;

return  result;

}

if (strstr(keyvaluebuf, keybuf) == NULL)

{

result = -1;

return result;

}

else

{

for (int i = 0; i < destlen; i++)

{

if (*keyvaluebuf == '=')

{

*keyvaluebuf++;

break;

}

keyvaluebuf++;

}

while(*keyvaluebuf != '\0')

{

*valuebuf = *keyvaluebuf;

valuebuf++;

keyvaluebuf++;

}

*valuebuf = '\0';

}

int len = strlen(valuebuf);

return result;

}

字符串项目开发模型

strstr+while语句进行符合条件字符串查找

demo04_两头堵

demo05_字符串反转

const专题讲座

1、 const基础知识(用法、含义、好处、扩展)

int main()

{

const int a;  //

int const b;

const int *c;

int * const d;

const int const *e ;

return 0;

}

Int func1(const )

初级理解:const是定义常量==》const意味着只读

含义:

//第一个第二个意思一样 代表一个常整形数

//第三个 c是一个指向常整形数的指针(所指向的内存数据不能被修改,但是本身可以修改)

//第四个 d 常指针(指针变量不能被修改,但是它所指向内存空间可以被修改)

//第五个 e一个指向常整形的常指针(指针和它所指向的内存空间,均不能被修改)

Const好处

//合理的利用const,

//1指针做函数参数,可以有效的提高代码可读性,减少bug;

//2清楚的分清参数的输入和输出特性

结论:

//指针变量和它所指向的内存空间变量,是两个不同的概念。。。。。。

//看const 是放在*的左边还是右边 看const是修饰指针变量,还是修饰所指向的内存空变量

04二级指针输入模型

二级指针内存模型图

 

数组名

1数组名

//二维数组也是线性排列的

void printArray(int *a, int size)

{

int i = 0;

printf("printArray: %d\n", sizeof(a));

for(i=0; i<size; i++)

{

printf("%d\n", a[i]);

}

}

int main()

{

int a[2][3] = {{1, 2, 3}, {4, 5, 6}};

char cc[10][30];

int* p = &a[0][0];

printf("sizeof(&a):%d \n", sizeof(&a));

printf("sizeof(a):%d \n", sizeof(a));

printf("sizeof(*a):%d \n", sizeof(*a));

printf("sizeof(&cc):%d \n", sizeof(&cc));

printf("sizeof(cc):%d \n", sizeof(cc));

printf("sizeof(*cc):%d \n", sizeof(*cc));

//printArray(p, 6);

getchar();

return 0;

}

2、本质分析

//int a[5] 一维数组名代表数组首元素的地址

//int a[5] ===> a的类型为int*

//二维数组名同样代表数组首元素的地址

//int b[2][5]===>b的类型为int(*)[5]

//测试如何测试:指针也是一种数据类型,它的数据类型是指它所执行的内存空间的数据类型

//如何测试b的步长?

//推导。。。。。。。

//结论:二维数组名 char cc[10][30] 是一个数组指针,char (*)[30]

2多维数组做函数参数退化

1、 C语言中只会以机械式的值拷贝的方式传递参数(实参把值传给形参)

int fun(char a[20], size_t b)
{
   printf("%d\t%d",b,sizeof(a));
}

原因1:高效

原因2:
C语言处理a[n]的时候,它没有办法知道n是几,它只知道&n[0]是多少,它的值作为参数传递进去了
虽然c语言可以做到直接int fun(char a[20]),然后函数能得到20这个数字,但是,C没有这么做。

2、二维数组参数同样存在退化的问题

二维数组可以看做是一维数组

二维数组中的每个元素是一维数组

二维数组参数中第一维的参数可以省略

void f(int a[5]) ====》void f(int a[]); ===》 void f(int* a);

void g(int a[3][3])====》 void g(int a[][3]); ====》 void g(int (*a)[3]);

3、等价关系

数组参数 等效的指针参数

一维数组 char a[30] 指针 char*

指针数组 char *a[30] 指针的指针 char **a

二维数组 char a[10][30] 数组的指针 char(*a)[30]

char * a[30]  char(*a)[30]  char(*a)(30)

怎么区分:指针数组、数组指针

3数组指

最新文章

  1. angularJs模块ui-router之路由控制
  2. Spring Web MVC 多viewResolver视图解析器解决方案
  3. [转] 《ES6标准入门》读书笔记
  4. Base64加密与MD5的区别?
  5. Django如何搭建服务器
  6. jQuery1.11源码分析(5)-----Sizzle编译和过滤阶段[原创]
  7. CDNJS:使用JavaScript CDN加速网站载入速度
  8. Why am I getting an error converting a Foo** → const Foo**?
  9. swift3.0 中NSNotification 的使用
  10. Java 8 中的 Streams API 详解
  11. [转] linux系统文件流、文件描述符与进程间关系详解
  12. Linux 的系统运行级别
  13. C++ ASCII 码的一些问题
  14. python 字典详解
  15. 【BZOJ2599】Race(点分治)
  16. react-redux-store
  17. 基于 jq 实现拖拽上传 APK 文件,js解析 APK 信息
  18. python伪装浏览器
  19. redis-5.0.3集群搭建
  20. 简单的实现微信获取openid

热门文章

  1. MySQL数据库 : 查询语句,连接查询及外键约束
  2. MySQL 如何查看及修改数据库引擎
  3. GMT 时间格式转换到 TDateTime (Delphi)
  4. 636. Exclusive Time of Functions
  5. jira安装说明
  6. 浅谈UWB(超宽带)室内定位技术(转载)
  7. 15、python之导入模块
  8. Keil如何生成bin文件【Keil生成Bin文件的方法】
  9. Mysql 表转换成 Sqlite表
  10. Web安全2--XSS&amp;CSRF