C语言温故而知新---Day01

Table of Contents

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

2、标准热身

3、 数据类型本质剖析

4、变量的本质

5、内存四区概念

6、指针铁律

7、经验:


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函数


#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);
//为什么这个地方换成了一个二级指针,而且又增加了一个接口 
int cltSocket_resvdata_Free2(unsigned char *buf); 

//4 客户端销毁环境
//为什么这个地方又加了一个* 4day
int cltSocket_destory2(void **handle);

#endif

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

2、标准热身

排序思想:

代码实现:

#include<stdio.h>
#include<stdlib.h>
#include<string.h>
void PrintfArray(int *a)
{
	for (int i = 0; i < 10; i++)
	{
		printf("%d ", a[i]);
	}
}

//1数组名做函数参数,会退化为指针
void PrintfArray02(int *a,int n)
{
	for (int i = 0; i < n; i++)
	{
		printf("%d ", a[i]);
	}
}

//2 在形参里面出现的char buf[30],int a[20], c/c++编译器,会把它当成指针,也不会主动地多分配内存
//day2后
void PrintfArray03(int a[10])
{
	int len1 = sizeof(a);
	int len2= sizeof(*a);
	int len = sizeof(a) / sizeof(*a);
	printf("len1=%d,len2=%d,len=%d,", len1, len2, len);
	for (int i = 0; i < len; i++)
	{
		printf("%d ", a[i]);
	}
}

void main()
{
	int a[10] = { 16, 21, 42, 26, 71, 19, 24, 34, 21, 54 };
	
	
	int len1 = sizeof(a);//数据类型不一样
	printf("排序前 %d:\n",len1);
	//for (int i = 0; i < 10; i++)
	//{
	//	printf("%d ", a[i]);
	//}
	PrintfArray03(a);
	for (int i = 0; i < 10; i++)
	{
		for (int j = i + 1; j < 10; j++)
		{
			if (a[i] < a[j])
			{
				int temp = a[i];
				a[i] = a[j];
				a[j] = temp;
			}
		}
	}
	printf("\n排序后:\n");
	//for (int i = 0; i < 10; i++)
	//{
	//	printf("%d ", a[i]);
	//}
	PrintfArray03(a);
	system("pause");

}

结论:

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

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

// 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的数据类型不一样

3、 数据类型本质剖析

数据类型问题抛出,压死初学者的三座大山

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种

#include<stdio.h>
#include<stdlib.h>
#include<string.h>
//typedef 对数据类型重新取个别名
typedef int u32;

//C 语言的灰色地带(C语言可以定义全局变量,但是JAVA语言不可以)
//int g_add;
//int g_add=10;

void main02()
{

	printf("%d \n", sizeof(u32));
	system("pause");
}
void main01()
{
	int b = 10;
	int a[10] = { 16, 21, 42, 26, 71, 19, 24, 34, 21, 54 };
	printf("a:%d,&a=%d\n", a, &a);//a和&a一样
	printf("a+1:%d,&a+1=%d", a+1, &a+1);//+1大小不一样
	//a和&a数据类型不一样,步长不一样

	system("pause");
}

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

//void *getTeacher()
//{
//	void *p = malloc(99);
//	return p;
//}

void main03()
{


	int a = 10;
	int *p;
	p = &a;
	//int a = 11;//直接修改
	printf("修改之前:%d \n", a);
	printf("%d \n", &a);

	*p = 20;//间接修改
	printf("修改之后:%d \n", a);
	system("pause");
}
void main04()
{

	int a = 10;//分配4个字节的内存,栈区也叫临时区
	int *p;//分配4个字节的内存,
	p = &a;//CPU执行的代码,在代码区
	*p = 20;

	{
		char *p = NULL;//分配4个字节的内存,栈区也叫临时区
		p = (char *)malloc(100);//内存泄露概念
		if (p != NULL)
		{
			free(p);
		}
	}
	system("pause");
}

结论:

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

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

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

4、变量的本质

修改变量的方法(三种)

第一种 直接赋初值,

第二种,找到变量的地址,在内存中修改

第三种,引用

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

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

总结:1对内存 可读可写; 2通过变量往内存读写数据,3不是向变量读写数据。4向变量代表的数据空间读写数据 

 

5、内存四区概念

基本概念

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

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

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

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

#define  _CRT_SECURE_NO_WARNINGS
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
void *getstring1()
{
	char *p1 = "abcde1";
	return p1;
}

void *getstring2()
{
	char *p2 = "abcde";
	return p2;
}

//void *getstring3(char **buf);
//
//void *getstring3(char(*buf)[30]);
void *getstring3(char buf[10][30])
{
//	char buf[30];
	char s[] = "abc";
	char *s1 = "abc";


	char **p2;
	char ***p4;
	//strcpy(buf, "abcde");
	return buf;
}

//void *getstring4()
//{
//	char *p2 = "abcde";
//	return p2;
//}


void main41()
{
	int i = 0;
	char *p1 = getstring1();
	char *p2 = getstring2();
	char ********p3 = NULL;//p3也是分配4个字节,它也是一个变量
	//char *p4 = getstring3();
	//printf("p1=%s\n", p1);
	//printf("p2=%s\n", p2);

	//printf("p1=%d\n", p1);
	//printf("p2=%d\n", p2);
	//printf("p4=%d\n", p4);


	//指针变量和她所指向的内存空间变量是两个不同的概念
	strcmp(p1, p2);
	system("pause");
}

void main42()
{
	//main41();
	system("pause");
}

 

6、指针铁律

 

 


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);

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


#define  _CRT_SECURE_NO_WARNINGS
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
void getData01(char *p1)//char *p1    是变量  是形参
//形参具有对外的属性
{
	printf("getData01() begin\n");
	return;

}

void getData02(char **p2)//char **p2   是变量  形参
//形参具有对外的属性
{
	printf("getData01() begin\n");
	return;

}

void getData03(char ***p3)//char ***p3     是变量  是形参
//形参具有对外的属性
{
	printf("getData01() begin\n");
	return;

}
//下面的变形,怎么写都无所谓,关键是理解的角度从两个角度出发
//站在C/C++编译器的角度出发,对形参,如果是指针类型(不管有几个*),C编译只会分配四个字节的内存
//指针的数据类型,到底是什么
//指针的数据类型是指他所指向的的内存的空间的数据类型,,具有依附属性
//指针的步长使用指针的数据类型的来决定的,比如char *p ;p++这样的步长就是1个字节
//int *p;p++ 步长就是4,以此类推,若
//void senddata01(char *p1);   void senddata01(char*       p1);
//void senddata02(char **p1);  void senddata02(char *     *p1);
//void senddata03(char ***p1); void senddata03(char *   **p1); void senddata03(char***    p1);
//void senddata04(char p[]);
//void senddata05(char *****p4);

void main61()
{
	char *p1 = NULL;
	char **p2 = NULL;
	int a = 10;
	int *p3 = NULL;
	a = 20;//直接通过变量修改地址
	p3 = &a;
	//*p放在等号的左边,去修改内存空间的值
	//*p放在等号的右边,从内存空间拿值(取值)
	*p3 = 30;//通过指针间接修改内存空间的值  
	int c = *p3;


	//*p的意义: *就像一把钥匙,根据一个指针变量的值,去修改门后的内存空间
	printf("p1:%d\n", sizeof(p1));
	system("pause");
}

void main62()
{
	char *p1 = NULL;
	char *p2 = NULL;

	char buf1[100] = {0};
	char buf2[100] = {0};
	strcpy(buf1, "abcdefg");
	p1 = buf1;
	p2 = buf2;
	while (*p1 != '\0')
	{
		*p2 = *p1;
		p1++;
		p2++;
	}
	
	system("pause");
}
void main63()
{
	//{
	//	//向NULL空间写数据 
	//	char *p = NULL; //写入位置 0x00000000 时发生访问冲突。0是操作系统用的地方
	//	*p = 100;
	//}


	//{
	//	char *p = 0x77;写入位置 0x00000077 时发生访问冲突。
	//	*p = 100;
	//}
	//{
	//	char *p = "abcdefg";//写入位置 0x01256960 时发生访问冲突。这个地址就是字符串的常量的首地址
	//	*p = 'z';
	//}
	//{
	//	//int *a = &10;//  10是字面量,不能取地址,,放在不能取地址,没有放在堆区,栈区,全局区,可以按照放在代码区之类的区域去理解他
	//	
	//}

	//{
	//	char *p = NULL;
	//	strcpy(p, "abcdef");
	//}
	system("pause");
}

//不断地修改指针的的值的含义
//需要建立场景,解决指针乱指的问题
void main()
{

	char buf[20];
	char *p = NULL;
	strcpy(buf, "123456789987654");
	p = &buf[0];
	p = &buf[1];
	p = &buf[3];
	p = &buf[4];
	p = &buf[5];
	p = &buf[6];
	for (int i = 0; i, 20; i++)
	{
		p = &buf[i];
	}

}

7、经验:

有关字面量的理解       

 


{

                   //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));

         }

 

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值