指针函数
指针函数:
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); //计算字符串可见长度,不包括\0
strcat(str,str); //字符串连接
strcpy(str,str); //字符串拷贝
_strlwr(str); //大写转小写
strupr(str); //小写转大写
void *memcpy(void *dest, void *src, unsigned int size);
//把资源内存(src所指向的内存区域) 拷贝到目标内存(dest所指向的内存区域);
//拷贝多少个?由一个size变量控制
#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;