(四)C 语言之指针专题二

1.1 1 理解指针必须和内存四区概念相结合
1.1.1 理论

  1. 主调函数 被调函数
    a)主调函数可把堆区、栈区、全局数据内存地址传给被调用函数
    b)被调用函数只能返回堆区、全局数据
  2. 内存分配方式
    a)指针做函数参数,是有输入和输出特性的
    b) 输入特性是指主调函数分配内存
    c) 输出特性是指被调函数分配内存,供主调函数使用
int getMem(char ** str1 /*out*/,int * len1  /*out*/,char ** str2  /*out*/,int * len2  /*out*/)
{
	char * tmp1 = NULL;
	char * tmp2 = NULL;
	tmp1 = (char*)malloc(sizeof(char) * 20);
	tmp2 = (char*)malloc(sizeof(char) * 30);
	strcpy(tmp1,"zhangsan");
	strcpy(tmp2,"list");
	*len1 = strlen(tmp1);
	*len2 = strlen(tmp2);
	*str1 = tmp1;
	*str2 = tmp2;
}

int main()
{
   char * str1 = NULL;
   char * str2 = NULL;
   int len1 = 0;
   int len2 = 0;
   getMem(&str1,&len1,&str2,&len2);

   printf("strl =%s\n",str1);
   printf("str2 = %s\n",str2);
   printf("len1 =%d\n",len1);
   printf("len2=%d\n",len2);

   if(str1 != NULL)
   {
	   free(str1);
	   str1 = NULL;
   }
   if(str2 != NULL){
	   free(str2);
	   str2 = NULL;
   }
  
  printf("zhangsan\n");
  return 0;

}

1.2 :应用指针必须和函数调用相结合(指针做函数参数)
1.2.1 理论部分
在这里插入图片描述
1.3 一级指针的典型用法

1.3.1字符串
1.3.1.1 字符串

  • C语言中的字符串是以零结尾的字符串
  • 在C语言中没有字符串类型,通过字符数组模拟字符串
  • 字符串的内存分配方式 : 堆,栈,全局区(重要

1.3.1.2实例

  1. 字符串和字符数组
int main()
{
	//不指定长度  C编译器会自动帮程序员 求元素的个数
	char buf1[] ={'a','b','c','d'}; //buf1是一个数组 不是一个以0结尾的字符串
	
	char buf2[64] = {'a','b','c','d'};  //后面的buf2[4]-buf2[63] 0
	// buf3[2] = {'a', 'b', 'c', 'd'}; //如果初始化的个数大于内存的个数 编译错误


  return 0;

}

2.求字符串的长度和字符数组的长度

  • //用字符串 来 初始化字符数组
  • //strlen() 长度 不包括0
  • //sizeof() 内存块的大小
int main()
{
	int size = 0;
	char buf3[] = "abcd"; // buf3 作为字符数组 应该是5个字节 //作为字符串 应该4个字节

	int len = strlen(buf3);
	printf("buf3字符的长度:%d \n", len); //4

	//buf3 作为数组 数组是一种数据类型 本质(固定小大内存块的别名)
	size = sizeof(buf3); //
	printf("buf3数组所占内存空间大小:%d \n", size); //5

	printf("hello....\n");

	{
		char buf4[128] = "abcd"; // buf
		printf("buf4[100]:%d \n", buf4[100]);
	}

  return 0;

}

// []的本质 :和*p 是一样 ,只不过是符合程序员的阅读习惯
// buf5 是一个指针, 只读的常量 buf5是一个常量指针 析构内存的时候,保证buf所指向的内存空间安全释放

1.3.2一级指针内存模型

int main()
{
	char buf[20]= "aaaa"; //定义并且初始化
	char buf2[] = "bbbb";
	char *p1 = "111111";
	char *p2 = malloc(100); 
	strcpy(p2, "3333");
	return 0;
}

在这里插入图片描述

1.3.3一级指针做输入

//*操作 和++的操作
//++ 优先级高 
void copy_str22(char *from, char *to)
{
	for (; *from!='\0';)
	{
		*to++ = *from++;  //  先 *to = *from;  再from++, to++ 
	}
	*to = '\0'; //

	return ;
}

void copy_str23(char *from, char *to)
{
	while( (*to = *from) != '\0' )
	{
		from ++; 
		to ++;
	}
}

1.3.4 一级指针做输入输出

//char *p = "abcd11112wq2abcd33qw33322abcd3333w322qwqqq"; 
//求字符串p中 abcd出现的次数
int getCount(char *mystr /*in*/, char *sub /*in*/,int *ncount /*out*/)
{
	int ret = 0;
	int tmpCount = 0;
	//初始化 让p指针达到查找的条件
	char *p = mystr; //不要轻易改变形参的值

	if (mystr==NULL || sub==NULL ||ncount==NULL)
	{
		ret = -1;
		printf("func getCount() err:%d (mystr==NULL || sub==NULL ||ncount==NULL) \n", ret);
		return ret;
	}

	do 
	{
		p = strstr(p, sub);
		if (p != NULL)
		{
			tmpCount++; //
			p = p + strlen(sub); //指针达到下次查找的条件
		}
		else
		{
			break;
		}
	} while (*p != '\0');

	*ncount = tmpCount; //间接赋值是指针存在的最大意义
	return ret;
}

1.4 二级指针的典型用法
1.4.1二级指针输出模型

  • 被调用函数分配内存

int  getMem(char ** myp1,int *mylen1,char **myp2,int *mylen2)
{
	char * tmp1= NULL;
	char * tmp2= NULL;
	tmp1= (char *)malloc(10);

	tmp2= (char *)malloc(20);
	strcpy(tmp1,"zhangsan");
	strcpy(tmp2,"lisilisi");
	*myp1= tmp1;
	*myp2= tmp2;
	*mylen1 =strlen(tmp1);
	*mylen2 =strlen(tmp2);
	return 0;
}

int getFree(char ** myp /*in*/)
{
	char * tmp = NULL;
	if(myp == NULL) return -1;
	tmp =*myp;
	free(tmp);
	*myp= NULL;   //这里用二级指针作为输入参数,可以避免野指针
	return 0;
}

int getFree0(char * myp)
{
	if(myp == NULL) return -1;
	free(myp);   //这里有野指针出现
}


int main()
{
	char  *p1 = NULL;
	int len1 = 0;

	char *p2 = NULL;
	int len2 = 0;
	getMem(&p1,&len1,&p2,&len2);
	printf("p1: %s \n", p1);
	printf("p2: %s \n", p2);
	//getFree0(p1);   //这里有野指针出现 ,如果释放两次p1,就会报错
	//getFree0(p1); 
	getFree(&p1);    //这里释放两个没有任何问题
	getFree(&p1); 

	
	return 0;
}

1.4.2 二级指针做输入的三种内存模型
1.4.2.1 二级指针做输入的第一种内存模型

void printArray1(char ** array,int num)
{
	int i =0;
	for(i =0;i< num ;i++)
	{
		printf("array[%d] = %s\n",i,array[i]);
	}
}
void sortArray1(char **array, int num )
{
	char * tmp = NULL;
	int i =0;
	int j =0;
	for( i =0 ;i<num ;i++)
	{
		for( j=i; j< num ;j++)
		{
			if(strcmp(array[i],array[j])> 0)
			{
				tmp =array[i];
				array[i] = array[j];
				array[j] = tmp;
			}
		}
	}

}
int main()
{
	//数组 数组中的每一个元素是指针 指针数组
	char * array[] ={"cccc","bbbb","aaaa","1111"};
	int num = sizeof(array)/sizeof(array[0]);
	printf("before sort \n");
	printArray1(array,num);
	sortArray1(array,num);
	printf("after sort \n");
	printArray1(array,num);
}

在这里插入图片描述

1.4.2.1 二级指针做输入的第二种内存模型


//问题的本质是:dm03_二级指针做输入_第2种内存模型 的 myArray + 1
				// dm03_二级指针做输入_第1种内存模型   myArray + 1 不一样 ;
//指针的步长不一样  指针所指向的内存空间的数据类不一样 。。。。

void printArray2_err(char ** array,int num)
{
	int i =0;
	for( i =0;i< num ;i++)
	{
		printf("array[%d] = %s\n",i,array[i]);
	}
}  
void printArray2(char  array[10][30],int num)
{
	int i =0;
	for( i =0;i< num ;i++)
	{
		printf("array[%d] = %s\n",i,array[i]);
	}
}  

void sortArray2(char array[10][30], int num )
{
	char tmp[30] ;
	int i =0;
	int j =0;
	for( i =0 ;i<num ;i++)
	{
		for( j=i ;j< num ;j++)
		{
			if(strcmp(array[i],array[j])> 0)  //交换的是内存块
			{
				strcpy(tmp,array[i]);              
				strcpy(array[i],array[j]);
				strcpy(array[j],tmp);
			}
		}
	}
}


int main()
{
	char array[10][30] ={"aaaaaa", "ccccc", "bbbbbbb", "2222222222"};
	printf("before sort \n");
	printArray2(array,4);
	sortArray2(array,4);
	printf("after sort \n");
	printArray2(array,4);

}
	char myArray[10][30] = {"aaaaaa", "ccccc", "bbbbbbb", "1111111111111"};
	//myArray: 编译器只会关心:有10行 ,每行30列。。。。。干什么?myArray+1  多维数组名的本质,

1.4.2.1 二级指针做输入的第三种内存模型


int getMem(char *** array,int num)
{
	char ** tmpArray= NULL;
	int i =0;
	if(array == NULL) return -1;
	tmpArray = (char **) malloc(sizeof(char*) * num);
	if(tmpArray == NULL) return -1;
	for( i = 0;i<num ;i++)
	{
		tmpArray[i]=(char*)malloc(sizeof(char) *100);
		sprintf(tmpArray[i],"%d%d%d",i+1,i+1,i+1);
	}
	*array = tmpArray;
	return 0;
}

void getFree(char *** array,int num)
{
	char ** tmpArray = NULL;
	int i =0;
	if(array == NULL) return ;
	tmpArray = *array;
	for(i =0 ;i< num ;i++)
	{
	 if(tmpArray[i]) free(tmpArray[i]); 
	}
	
	free(tmpArray);
	*array= NULL;
}

void printArray(char ** array,int num)
{
	int i =0;
	for(i =0;i< num ;i++)
	{
		printf("%s\n",array[i]);
	}
}

void sortArray(char ** array,int num)
{
	int i=0,j=0;
	char * tmp =NULL;
	if(array == NULL) return ;
	for(i =0;i<num ;i++)
	{
		for(j =i+1;j<num ;j++)
		{
			if(strcmp(array[j],array[i])>0)
			{
				tmp =array[i];
				array[j] =array[j];
				array[j]=tmp; 
			}
		}
	}
}

int main()
{
	char **p2 = NULL;
	int num = 5;
	char *tmp = NULL;
	getMem(&p2,num);
	printArray(p2,num);
	getFree(&p2,num);
	return 0;
}

1.4.2.1 二级指针三种内存模型内存图

在这里插入图片描述

1.5 案例
// 有一个字符串符合以下特征(”abcdef,acccd,eeee,aaaa,e3eeeee,sssss,";)

int  splitStr(const char * mystr,char c,char ***mysubstr,int *len)
{
	//计算c出现的次数
	int count = 0;
	int i =0;
	char * p1 = NULL;
	char * p2 = NULL;
	char **tmp = NULL;
	p1= mystr;
	do{
		p1 =strchr(p1,c);
		if(p1) {
			count++;
			p1 = p1 +sizeof(char);
		}
		else{
			break;
		}
		
	}while(*p1 != '\0');
	*len = count;
	
	tmp = (char**)malloc(sizeof(char*) * count);
	if(tmp == NULL) return -1;
	for( i =0 ;i< count;i++)
	{
		tmp[i] = (char*)malloc(sizeof(char)*30);
	}
	p1 = mystr;
	p2 = mystr;
	for(i =0 ;i<count;i++)
	{
		p2 = strchr(p1,c);
		if(p2 == NULL) break;
		strncpy(tmp[i],p1,p2-p1);
		tmp[i][p2-p1] ='\0';
		p1 = p2 +1;
	}
	*mysubstr = tmp;
	return 0;
}

void printArray(char ** array,int num)
{
	 int i =0 ;
	 for(i = 0;i <num ;i++)
	 {
		 printf("array[%d] = %s\n",i,array[i]);
	 }
}
int main()
{	
	char ** spl = NULL;
	int count = 0;
	char *str ="abcdef,acccd,eeee,aaaa,e3eeeee,sssss,";
	splitStr(str,',',&spl,&count);
	printf("count =%d\n",count);
	printArray(spl,count);
}

参考一 : 狄泰软件课程
参考二 : 传智扫地僧老师课程
如有侵权:请联系邮箱 1986005934@qq.com

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值