C语言~指针进阶(1)
一维数组指针
数组名:可以代表首地址,那么咱们就可以用指针指向数组。
虽然数组名可以代表一个元素首地址,但是它是个常量,不能自增或者自减!但是可以创建一个指针指向数组,然后++。
int arr[10];
arr++; // error E0137 表达式必须是可修改的左值
// error C2105 “++”需要左值
printf("%p \n", arr); //1 004FF810,代表第一个元素地址
printf("%p \n", &arr);//2 004FF810,代表整个数组 1,2的值一样但是意义完全不同
printf("%p \n", arr + 1); //3 004FF814 跳过一个元素
printf("%p \n", &arr + 1);//4 004FF9A0 跳过了一个数组
int arr[6] = {0,1,2,3,4,5};
//p是个指针变量,可以任意操作 &arr[0]==arr
int* p = &arr[0];
p++;
printf("%d", *(p++));//输出结果:1
//&arr的类型是:int (*)[6]指向整个一维数组的类型
int a = &arr;//error:C2440 “初始化” : 无法从“int(*)[6]”转换为“int”
int(*pp)[6] = &arr; //正确的做法
二维数组指针
//定义一个二维数组
int map[5][2] = { 1,2,3,4,5,6,7,8,9,10 };
//定义指针指向二维数组
//int a = ↦ //error: C2440 “初始化” : 无法从“int(*)[5][2]”转换为“int”
int(*p)[2] = ↦//(*p)为了让p先于*结合,成为一个指针,[2]是二维数组列数
p+1得到的是map[1]地址,因为map[1]里包含map[1][0],map[1][1] 所以不能直接*(p+1)来获取数值,
只能**(p+1)来获取
//p+1==map[1] map[1][0]==**(p+1)
printf("\n%d", *(p + 1));//输出结果:4585576 /*警告 C6273 传递了一个非整数作为_Param_(2),而对“printf”的调用需要一个整数,实际类型: “int[2]” : 如果当前传递的是一个指针值,则应使用 % p */
printf("\n%d", **(p + 1));//输出结果:3 等价于(*(p+1))[0]
printf("\n%d", map[1][1]);//4
printf("\n%d", (*(map + 1))[1]);//4 map+1==&map[1] *(p+1)==map[1]第一个元素首地址 (*(p+1))[1]==(*(map+1))[1]
printf("\n%d", (**(map + 1))+1);//4
内存四区
-
栈区:放在栈区的变量,生命周期结束自动释放内存 例如:int age=3;
-
堆区:需要手动申请,需要手动释放,如果忘记释放就会导致内存泄漏
-
全局区:静态变量 全局变量 常量(不是const定义的)
-
代码区:代码,二进制代码
int num = 0;//栈区
const double p = 3.14;//栈区
static aa = 0;//全局区
char arr[] = "hello";//栈区
"hello";//全局区(常量区)
printf("%p %p", arr, "helllo");//输出结果:007FFB9C 00F67BCC
动态内存分配
malloc
//动态内存分配,在堆区
int* pa = (int*)malloc(sizeof(int));
//防御性编程
if(pa == NULL)
{
return -1;//如果申请失败返回-1
}
//使用
*pa = 18;
printf("%d", *pa);//输出结果:18
//不要改变pa指向,如果改变了,释放就会出错,内存会泄露,后果很严重
(*pa)++;
printf("\n%d", *pa);//输出结果:19
//如果实在改变了要在释放内存前恢复原样再释放
(*pa)--;
//释放内存
free(pa);
pa = NULL;//释放后再置空,后面再使用这个内存就会报错
危险:使用了释放了的内存
//*pa = 6666;
//printf("\n%d", *pa);
realloc
# include <stdio.h>
# include <string.h>
# include <stdlib.h>
# define BABY_NUM 61
int main()
{
//定义一个数组存储所有同学年龄
//int ages[61];//虽然这样也可以,但是不够灵活,要是同学少于61则浪费内存,多余61数组又不够大
int* ages = (int*)malloc(sizeof(int)* BABY_NUM);
if (!ages)
{
return -1;
}
for (int i = 0; i < BABY_NUM; i++)
{
*(ages + i) = 19;
printf("%d\n", ages[i]);
}
printf("\n");
//怎么调整大小?realloc传进去的内存已经释放掉了,返回的是新的内存地址
int* Newages = (int*)realloc(ages, sizeof(int) * 59);
if (!Newages)
{
Newages = ages;
//free(ages);
return -2;
}
for (int j = 0; j < 59; j++)
{
printf("%d", Newages[j]);
}
free(Newages);
return 0;
}
calloc
# include <stdio.h>
# include <string.h>
# include <stdlib.h>
int main()
{
int capacity = 10;//容量
int* pa = (int*)malloc(sizeof(int) * capacity);//malloc不会自动初始化
memset(pa, 0, sizeof(int) * capacity);//清空数组内存
for (int i = 0; i < capacity; i++)
{
printf("%d", pa[i]);//如果不用memset输出结果:-842150451-842150451...垃圾值
}
printf("\n");
int* pa2 = (int*)calloc(capacity, sizeof(int));//calloc自动初始化为0
for (int i = 0; i < capacity; i++)
{
printf("%d ", pa2[i]);//输出结果:0 0 0 0 0 0 0 0 0 0
}
//别忘了释放置空
free(pa);
pa = NULL;
free(pa2);
pa2 = NULL;
return 0;
}
指针数组
//指针数组
//数组里的元素都是int型指针
int* arr[5] = { NULL };
for (int i = 0; i < 5; i++)
{
arr[i] = (int*)calloc(5, sizeof(int));
for (int j = 0; j < 5; j++)
{
arr[i][j] = j;
}
}
for (int i = 0; i < 5; i++)
{
for (int j = 0; j < 5; j++)
{
printf("%d ", **(arr+1)+j);
}
printf("\n");
}
for (int i = 0; i < 5; i++)
{
free(arr[i]);
}
补充
char* p[]
:首先是一个数组,每个元素为一个指向字符(串)的指针
例如char* p[3] = { “111”, “222”, “333”}:[
的优先级高于 *
意味着p是一个有3个元素的数组 元素的类型是 char*
。或者可以理解将p和[3]在一起,则p[3]
是个数组,p存放的是数组中首个元素的地址,数组里存放的 char*
类型的数据,char* 类型即是指针类型,也就是里面是指针,即:某个变量的地址。
可参考文章: