c-指针进阶篇,字符串函数

指针函数

指针函数:
1.参数是指针
    1.1 在子函数中,修改普通的实参的值,传的是普通实参的地址(一级指针),在函数中修改是*一级指针
    1.2 在子函数总,修改指针的实参的值,传的是指针实参的地址(二级指针),在子函数中修改是*二级指针

指针最基本的使用

void modify(int* a)	//int *a=#  赋值操作,形参,实参类型一致
{
	*a = 1001;	//*一级指针
}    //在子函数中,修改普通的实参的值,传的是普通实参的地址(一级指针),在子函数中修改是*一级指针
int main() 
{
	int num = 1;
	modify(&num);		
	printf("%d\n", num);
	int aa = 1;
	int bb = 1001;
	return 0;
}
在子函数中,修改的是*a

在这里插入图片描述
交换a,b的值,使其可以在主函数当中输出

void Swap(int* a, int* b) //交换a,b的值,使其可以在主函数当中输出
{
	int temp = *a;
	*a = *b;
	*b = temp;
}   //子函数当中修改了函数的值
int main()
{
    int aa = 1;
	int bb = 1001;
	Swap(&aa, &bb);  //传参就系要传实参的地址
	printf("a=%d,b=%d\n", aa, bb);
    return 0;    
}

在子函数总,修改指针的实参的值,传的是指针实参的地址(二级指针),在子函数中修改是*二级指针

int g_num = 1001;
void modifyPoint(int** p)  //在当前函数中修改指针的指向,由p指向num改为p指向g_num
{    //在子函数总,修改指针的实参的值,传的是指针实参的地址(二级指针),在子函数中修改是*二级指针
	*p = &g_num;  //修改p的指向需要p的地址,就要传二级指针**p
}

int main()
{
    num = 1111;
	int* p = #
	modifyPoint(&p);
	printf("%d\n", *p);
	returnPremer2(p);
    return 0;    
}
2.反回值是指针
	2.1 不能返回局部变量地址
    2.2 规定用int类型的返回变量,int*类型的返回变量的地址,int返回变量
int* returnNum() //合法
{
	return &g_num;
}
//int a 是局部变量 不能返回局部变量的地址
int* returnPremer(int a)   //1
{
	return &a;  //return 1对 return &1错
}
int* returnPremer2(int* a)  //传入的是指针变量的值,不是局部变量 
{		
	return  a;				//所以返回指针变量的值  
}

数组中

//在数组中
void  initArray(int array[], int arrayNum)   //传数组的专用写法
{
	for (int i = 0; i < arrayNum; i++)
	{
		array[i] = i;
	}
}                           
void initArray2(int* array, int arrayNum)   //传指针或地址的写法
                                            //int array[],int* array两种写法等效 
{                                           //相当于传一级指针
	for (int i = 0; i< arrayNum; i++)//array 等效于&array[0](第一的元素的地址)  int *array
	{
		array[i] = i;
	}
}

字符串函数(string.h)

int  strcmp(char const* _Str1, char const* _Str2);//字符串比较函数
                                                  //str1>str2 返回值大于0  1
	                                              //str1==str2  0
	                                              //str1<str2  -1
strlen(char const* _Str);                    //计算字符串可见长度
strcat(str,str);                                    //字符串连接
strcpy(str,str);                                    //字符串拷贝 

#include <string.h>  //字符串处理头文件
#include <stdio.h>
int main() 
{
	//int  strcmp(char const* _Str1, char const* _Str2);
	//str1>str2 返回值大于0  1
	//str1==str2  0
	//str1<str2  -1
	char str1[] = "ABC";
	char str2[] = "ACB";
	char str3[] = "ACB";
	//mystrcmp
	if (strcmp(str1, str2) > 0) //
	{
		printf("str1>str2\n");
	}
	if (strcmp(str2, str3) == 0) 
	{
		printf("str2==str3\n");
	}
	//size_t 等效 unsigned int
	//size_t  strlen(char const* _Str);
	printf("%d\n", strlen(str1));
	int size = strlen(str1) + 1;  // +\0
	//字符串连接 strcat
	char strInfo[1024] = "ILoveyou";
	strcat(strInfo, str1);  //字符串必须要空间足够,前面的字符串必须大于两个字符串的总长度
	puts(strInfo);            //打印字符串
	//字符串拷贝 strcpy
	//C语言中操作字符串不能直接赋值 
	char strA[] = "ILoveLOUU";
	char strB[] = "IMissYou";
	//strA = strB;  不能直接赋值
	strcpy(strA, strB);	/*一定要能装的下,第一个要大于等于第二个,一般用于字符串赋值,和
	作用原理,把第一个清空掉在赋值,数组申请的空间长度空间长度不会改变,装不下的话会溢出*/
	printf("strA:%s\n", strA);
	printf("strB:%s\n", strB);
	//字符串函数都是处理到\0
	char str11[10] = "abc";  
	char str22[12] = "ABCD";
	strcpy(str11, str22);
	puts(str11);
	//不常见的: 
	//1.大写转小写
	char ABC[] = "ABCDd";
	_strlwr(ABC);//'_'是vs对函数做了修改
	puts(ABC);
	//2.小写转大写
	_strupr(ABC);
	puts(ABC);
	return 0;
}

字符串赋值溢出时报错,顺便教几个单词
溢出情况

动态申请内存

1.动态申请内存
动态申请的内存是堆内存,特点 人为申请,手动释放
size_t 就是 unsigned int  无符号整型的另一个名字(正整数)
void *malloc(size_t size);  使用时需要强制转换
 (int*)malloc(sizeof(int))
 前面(int*)是: 指针类型				//去掉变量名
 后面是(int): 指针所指向的类型		//去掉变量名和* 你要存储的数据类型
2.free(void *point);
3. 野指针: 没有指向的指针
	NULL :通常会给指针一个指向

动态内存申请的格式

void *malloc(size_t size);  //void *说明使用malloc函数时需要强制转换

释放格式

free(void *point);

只申请一个变量内存

//只申请一个变量内存
int* pInt = (int*)malloc(sizeof(int));
//指针变成变量,有两种方式
//1.指向变量的地址
*pInt1001;//*+地址就是一个变量
//int* pVoid = NULL;
//*pVoid=1001;   *pVoid不能被改变,NULL是空,相当于0,是常量,常量不能改变

//2.申请堆内存,只要申请了堆内存,它就是一个变量

动态内存申请的好处

int* malloNum() //所做的操作会被保留
{
	int* p = (int*)malloc(sizeof(int));
	*p = 1002;
	return p;
}

申请一段内存: 数组

    int arrayNum = 0;
	scanf("%d", &arrayNum);
	int* pArray = (int*)malloc(sizeof(int) * arrayNum);	//pArray[5],申请数组
	for (int i = 0; i < arrayNum; i++) 
	{
		pArray[i] = i;
		printf("%d\t", pArray[i]);
	}
	printf("\n");
	//释放一定要置空
	free(pInt);//释放指针
	pInt = NULL;
	free(pArray);
	pArray = NULL;

通过二级指针去理解二维数组

int** makeArray2D(int row, int cols) 
{	
	//int *array --->array[i] 存放多个整数
	//int **p--->(*p)[i] 存放多个一级指针
	//p[i]---> 存放多个整数
	//二级指针如何变成二维数组
	int  **p = (int **)malloc(sizeof(int*) * row); //指针类型(int **),
	for (int i = 0; i < row; i++) 
	{
		p[i] = (int*)malloc(sizeof(int) * cols);
	}
	return p;
}
int main()
{
    //通过二级指针去理解二维数组
	//二级指针如何变成二维数组
	int** array2D = makeArray2D(2, 2);
	array2D[1][1] = 1001;
	printf("%d\n", array2D[1][1]);
	free(array2D);
	array2D = NULL;
    return 0;
}

释放问题:在哪里申请的, 在哪个位置释放

//释放问题: 在哪里申请的, 在哪个位置释放
	int* pMove = (int*)malloc(sizeof(int) * 3);
	//正常的使用
	pMove[0] = 1;
	pMove[1] = 2;
	pMove[2] = 3;
	//做了指针指向的改变
	pMove++;                //此时pMove指向pMove[1]
	//pMove[i]等效于 *(pMove+i) 指针的运算
	printf("pMove[-1]=%d\n", pMove[-1]);
	//释放前要还原指针原来的指向
	--pMove;
	free(pMove);//从哪里申请就要从哪里释放
	pMove = NULL;

其他释放函数

//1
	//malloc申请的内存是没有初始化,存放的是垃圾值
	//void * calloc(size_t count,size_t size); 申请内存过程中初始化
	int* pMalloc = (int*)malloc(4 * sizeof(int));
	memset(pMalloc, 0, sizeof(int) * 4);		//设置内存每个字节的值
	int* pCalloc = (int*)calloc(4, sizeof(int));//(4, sizeof(int))相当于(4 * sizeof(int))
	                      //以上三句话中,前两句话相当于第三句话
	free(pMalloc); //使用完后要释放
	pMalloc = NULL;//一定要为空,否则成为野指针
	free(pCalloc);
	pCalloc = NULL;
//2
	//为指针重新申请内存
	//void *realloc(void *p,size_t size);

	int* pRealloc = (int*)malloc(sizeof(int) * 2);
	pRealloc[0] = 1;
	pRealloc[1] = 2;
	printf("%p\n", pRealloc + 1);
	printf("%p\n", pRealloc + 2);
	pRealloc=(int *)realloc(pRealloc, sizeof(int) * 4);//重新申请的空间一定要比上次的大
	                               //该返回值指向重新申请的空间的首地址
	pRealloc[2] = 3;
	pRealloc[3] = 4;
	printf("%p\n", pRealloc + 1);
	printf("%p\n", pRealloc + 2);
	for (int i = 0; i < 4; i++) 
	{
		printf("%d\t", pRealloc[i]);
	}
	printf("\n");
	free(pRealloc);
	pRealloc = NULL;

指针数组与数组指针

1.如何区分指针数组,数组指针
   看主谓宾
   整形数组: 存放的整数的数组,他是多个整数
   指针数组: 指针的数组  --->他是数组
            存放多个指针的数组,他是多个指针
   数组指针: 数组的指针  --->他是一个指针
2. 功能
   2.1 指针数组一般是用来操作字符串
   2.2 数组指针-->表示二维数组
       2.2.1 变成二维数组
       2.2.2 当做二维数组的指针使用

指针数组
一般是用来操作字符串

    //指针数组
	int a = 1;
	int b = 2;
	int c = 3;
	int* pInt[3];//每一个pInt[i]都可以存放一个指针,数字类比较少用
	//pInt[i] 多个一级指针
	pInt[0] = &a;
	pInt[1] = &b;
	pInt[2] = &c;
	const char* p = "ILove";//一级指针可以操作一个字符串,所以常用指针数组操作多个字符串
	const char* pStr[3] = {"ILove","IMissyou","wantyou"};
	for (int i = 0; i < 3; i++) 
	{
		puts(pStr[i]);//pStr[i]是一级指针,puts自动换行
		//好处,每个字符串的申请空间可以不相同
	}

数组指针
可以表示二维数组
2.2.1 变成二维数组
2.2.2 当做二维数组的指针使用
传二维数组时的一个错误做法

void print(int array[][3], int row, int cols)
{
	for (int i = 0; i < row; i++)
	{
		for (int j = 0; j < cols; j++)
		{
			printf("%d\t", array[i][j]);
		}
		printf("\n");
	}
}
int main()//真正的二维数组其实不是二维指针
{
	int array[2][3] = { 1, 2, 3, 4, 5, 6 };
	//“函数”:“int (*)[3]”与“int **”的间接级别不同
	int **p = array;
	print(p, 2, 3);  //按规矩来说其实本身不允许这样写
	//c语言中可以运行,但是会有问题,如下图。但是c++中会报错
	return 0;
}

当看到有以下问题时,将其当做错误代码处理
在这里插入图片描述

这些都是因为指针的类型不一致,一般情况下数组与二级指针是有区别的,所以一般情况下我们传的是数组指针
正确做法将后半段改为

    int array[2][3] = { 1, 2, 3, 4, 5, 6 };
    //数组指针
	int (*p)[3] = array;   //这里做了改变
	//*优先跟p结合在一起,就形成了一个指针,这个指针是指向一个数组的,这个数组的长度是三
	print(p, 2, 3);

数组指针如何申请内存
变成二维数组

    //数组指针如何申请? 让他变成二维数组
	//(指针的类型)malloc(sizeof(指针所指向的类型)*n);
	//指针的类型:去掉变量
	//指针所指向的类型:去掉变量名和*
	int(*pArray)[3] = (int(*)[3])malloc(sizeof(int[3]) * 2);	//等效 int pArray[2][3];
	for (int i = 0; i < 2; i++) 
	{
		for (int j = 0; j < 3; j++) 
		{
			pArray[i][j] = i + j;
			printf("%d\t", pArray[i][j]);
		}
		printf("\n");
	}
	free(pArray);
	pArray = NULL;
©️2020 CSDN 皮肤主题: 1024 设计师:上身试试 返回首页