1.经常容易混淆的指针
1.int *a[10];
这是一个指针数组,数组a中有10个整型的指针变量(常用语保存多个字符串)
int a,b,c;
int *pa[3]; //指针数组pa,每个元素可以存储的是地址
pa[0] = &a; //元素0保存的是变量a的地址
pa[1] = &b;
pa[2] = &c;
2.int (*a)[10]
这是一个数组指针,常用于定义一个行指针,用于保存二维数组的地址;二维数组的形参可以定义为数组指针变量。
int (*a)[10];
int arr[2][3] = {0};
a = arr; //数组指针a,指向二维数组arr
如果它加1的话,指向二维数组的下一行的行首地址。
3.int **p;
这是一个指针的指针,保存指针变量的地址,也称二级指针;搭配指针数组使用。
//经常容易混淆的指针
#include<stdio.h>
int main()
{
int arr[10] = {1,2,3,4,5,6,7,8,9,10};
int **p;//定义一个二级指针
int *q[10];//定义一个指针数组,数组中的每一个元素是一个指针
int i;
for(i=0;i<10;i++)
{
q[i] = &arr[i];
}
p = &q[0];
printf("%p\n",p);
printf("%p\n",q[0]);
printf("%p\n",*p);
printf("%p\n",++p);
printf("%p\n",q[1]);
return 0;
}
2.只读指针变量
int a = 100;
int b = 200;
int * const p = a; //只读指针变量 const修饰的是*,即指针变量不能变
*p = 300; //正确,指针所指向的内容可以改变
p = &b;//错误,指针的指向标不可以改变,即指针的值不能改变
2.只读变量指针
int a = 100;
int b = 200;
int * const p = a; //只读指针变量 const修饰的是int,即数据变量不能变
*p = 300; //错误,指针所指向的内容不可以改变
p = &b;//正确,指针的指向标可以改变,即指针的值能改变
3.1.int *f(void);
注意:f没有用括号括起来,说明f是一个函数,*修饰返回值类型,因此是指针函数。他是一个函数的声明,声明这个函数的返回值为int *类型的。
2.int(*f)(void);
注意:*f用括号括起来了,*修饰f说明,f是一个指针变量,因此是函数指针。f是个函数指针变量,存放函数的地址,他指向的函数必须有一个int类型返回值,没有参数。
2.动态内存申请
概述:数组定义时,数组长度是预先定义好的,整个程序中固定不变。但实际编程中,往往需要根据实际情况申请空间。
C语言提供了一些内存管理函数,可以通过需要动态分配内存空间,也可以把不在使用的空间回收。
3.静态分配
1》在编译或者运行时,按事先规定的大小分配空间,比如int a[10],系统自动分配。
2》必须事先指定所需空间大小。
3》分配在栈区或全局变量区,一般以数组形式
4》按计划分配
int a = 10; //这个就是静态分配(系统自动分配)
4.动态分配
1》在程序运行中,根据需要大小自由分配,需要程序员自己分配
2》分配在堆区,一般使用特定函数进行分配
3》按需分配
int *p;
//用malloc申请一个存10个int型元素的数组
p = (int *)malloc(sizeof(int)*10);
if(p==NULL)
{
printf("error\n");
}
5.动态分配函数
1》malloc函数:开辟一片连续的内存空间,需要手动初始化
语法:指针变量接收 = malloc (需要开辟的空间大小字节数)
指针变量接收 = malloc (元素类型字节数*元素个数)
注意指针变量类型需要开辟所需的数据类型保持一致
//这个函数是给malloc手动初始化函数
memset(p,0,40); // memset函数对申请的空间初始化 memset是否可以置其余的值
//memset() 查找这个函数在#include<string.h>这个头文件查找
int i;
for(i=0;i<10;i++)
{
p[i] = i;
printf("%d\n",p[i]);
}
2》free函数
语法:free(指针变量)
free(p);//如果没有释放申请的空间 ,会造成内存泄漏, 内存泄漏是指只申请不释放。
p = NULL;//防止称为野指针
3》calloc函数:开辟一片连续的内存空间,==自动初始化为0==
语法:指针变量接收 = calloc(元素个数,元素类型所占的字节数)
#include<stdio.h>
int main()
{
int *p;
p = (int *)calloc(20,sizeof(int)*20); //calloc()等价于mallco()和memset()
if(p == NULL)
{
printf("error\n");
}
int i;
for(i=0;i<20;i++)
{
p[i] = i;
printf("%d\n",p[i]);
}
free(p);
p = NULL;
return 0;
}
4》recalloc函数:重新分配 (或称修改已分配的)内存空间大小,主要是进行扩展内存空间。
语法:指针变量接收 = recalloc(已分配存储区指针变量,重新分配空间大小的字节数)
p = realloc(p,100);//realloc用来对空间进行扩容,原来数据保留,新增加的空间值是随机的
{
if(p==NULL)
{
printf("error\n");
}
}
//初始化扩容的数据第一种方法
// int *pa;
// pa = p;
// pa = pa+10;
// memset(pa,0,60);
//初始化扩容的数据第二种方法
// memset(p+10,0,60);
//初始化扩容的数据第三种方法
// for(i=10;i<25;i++)
// {
// p[i] = 0;
// }
for(i=0;i<25;i++)
{
// p[i] = i;
printf("%d\n",p[i]);
}
上面有重新分配后,将扩容的函数进行初始化的是那种方法!!!
4.内存泄漏
内存泄漏概念:申请的内存,首地址丢了,找不到了,再也没有办法使用了,也没有办法释放,这块内存就泄露了
char *p;
p = (char *)malloc(100); //p指向申请的地址
p = "hello world"; //p重新指向了字符串,之前申请的地址将无法找到