目录
指针对于C语言而言是至关重要的,下面是我学习指针的一些学习路线和个人想法,写的不好,希望各位大佬不吝指教。
🍎指针的概念:
指针就是变量,用来存放地址,地址唯一标识一块内存空间。
指针的大小是固定的4/8个字节(32位平台/64位平台)。
指针是有类型,指针的类型决定了指针的+-整数的步长,指针解引用操作的时候的权限。
指针的运算
🍎1.字符指针
常量字符串放在只读,代码段
🍌列1:
int main()
{
const char* p = "abcdef";//"abcdef"为常量字符串
printf("%s\n", p);
//p为常量字符串首元素的地址,打印的为字符串格式(%s),会沿着首地址打印,直到遇到'\0'
printf("%c\n", p);
//p为指针变量,为地址,无法根据地址打印字符
printf("%c\n", *p);
//*p==a,%c打印一个字符,打印a
printf("%s\n", *p);
//*p==a,%s为沿字符串首地址打印字符串,直到遇到‘\0’,此时无法打印
return 0;
}
🍌列2:
int main()
{
char* p1 = "abcdef";//常量字符串不能修改,p1,p2只存储了一份,指向同一块空间的存储位置
char* p2 = "abcdef";
if (p1 == p2)
{
printf("p1==p2");
}
else
{
printf("haha");
}
return 0;
}
- 判断字符串是否相等使用strcmp函数,==是判断地址是否相等的
✍内存展示
🍎2.指针数组
本质是数组,用来存放指针
int* arr1[10];//整形指针数组——存放整形变量的地址
char* arr2[4];//一级字符指针数组——存放字符变量的地址
char** arr3[5];//二级字符指针数组——可存放一级字符指针的数组
- 指针变量\数组在一定情况下可以存放整形变量的值,它的空间是可以存放的,但在C的语法中是不正确的
🍌代码:
int main()
{
int arr1[] = { 1,2,3,4,5 };
int arr2[] = { 2,3,4,5,6 };
int arr3[] = { 3,4,5,6,7 };
int* parr[] = { arr1,arr2,arr3 };
for (int i = 0; i < 3; i++)
{
for (int j = 0; j < 5; j++)
{
printf("%d ", *(parr[i] + j));
//printf("%d ", *(*(parr + i) + j));
}
printf("\n");
}
return 0;
}
🍌int* parr[]内存原理:
✍*(parr[i] + j)
✍*(*(parr+i) + j))
🍎3.数组指针
🍌3.1数组指针的定义
-
数组指针是指针,它存放数组地址,而非指向数组本身
整形指针: int * pint; 能够指向整形数据的指针。 浮点型指针: float * pf; 能够指向浮点型数据的指针。
数组指针:指向数组的指针
int *p1[10];
int (*p2)[10];
//p1, p2分别是什么?
int (*p)[10]; //解释:p先和结合,说明p是一个指针变量,然后指着指向的是一个大小为10个整型的数组。所以p是一个 指针,指向一个数组,叫数组指针。 //这里要注意:[]的优先级要高于号的,所以必须加上()来保证p先和*结合
✍注意:
数组指针可以利用二级指针的方式获得数组内的值,但是不可以使用二级指针的方式接收数组指针
- 不能用二级指针接收数组指针
✍练习:
int main()
{
char arr[5] = { 1,2,3,4,5 };
char(*p1)[5] = &arr;
//(*p1)表示指针,指向数组arr的地址,[5]表示指针所指向的5个元素,int表示数组的练习
return 0;
}
- *p1的类型为int [5],相当于将一维数组的数组名取出后的类型
🍌3.2&数组名和数组名
int main()
{
int arr[10] = { 0 };
printf("arr = %p\n", arr);
printf("&arr = %p\n", &arr);
printf("arr+1 = %p\n", arr + 1);
printf("&arr+1 = %p\n", &arr + 1);
return 0;
}
&arr表示的是数组的地址,所以+1后直接跳过了整个数组的。
arr表示首元素的地址
但它们指向相同的地址
✍数组名不是首元素地址的情况
-
&数组名
-
sizeof(数组名):在sizeof内数组名必须单独出现
✍思考题
int main()
{
int arr[10] = { 1,2,3,4,5,6,7,8,9,10 };
int(*pa)[10] = &arr;//数组指针
//pa为数组&arr,(*pa)为arr数组首元素的地址,pa为指针变量
//方法1
for (int i = 0; i < 10; i++)
{
printf("%d ", (*pa)[i]);
//pa为数组&arr,(*pa)为arr,相当于arr[i]
}
printf("\n");
//方法2
for (int i = 0; i < 10; i++)
{
printf("%d ", *(pa + i));
//pa为数组的地址,每次多加1,相当于地址增大一个arr数组的大小
}
printf("\n");
//方法3
for (int i = 0; i < 10; i++)
{
printf("%d ", *pa + i);
//*pa=arr,每次加1,地址增加一个整形的大小,打印出的是地址
}
printf("\n");
//方法4
for (int i = 0; i < 10; i++)
{
printf("%d ", *(*pa + i));
//数组arr的地址由pa接收,表面在这个条件下,可以指针变量可以经历两次解引用
//第一次解引用为数组的地址解引用,获得首元素的地址
//第二次首元素的地址解引用,获得该地址指向的空间内的值
//由方法3得,(*pa+i)是arr数组中元素得地址,通过再次解引用得到各元素值
}
printf("\n");
return 0;
}
🍌3.3.数组指针的使用
- 数组指针在二维数组应用中常见
✍代码
void print1(int arr[3][5], int row, int col)
{
for (int i = 0; i < row; i++)
{
for (int j = 0; j < col; j++)
{
printf("%d ", arr[i][j]);
}
printf("\n");
}
}
void print2(int(*p)[5], int row, int col)
{
for (int i = 0; i < row; i++)
{
for (int j = 0; j < col; j++)
{
//printf("%d ", p[i][j]);
printf("%d ", *(*(p+i)+j));
//*(p+i)==p[i]
//*(*(p+i)+j)==p[i][j]
}
printf("\n");
}
}
int main()
{
int arr[3][5] = { {1,2,3,4,5},{2,3,4,5,6},{3,4,5,6,7} };
//数组名arr,为首元素的地址
//但是二维数组的首元素是二维数组的第一行
//所以这里传递的arr,其实相当于第一行的地址,是一维数组的地址
//可以用数组指针接收
print1(arr, 3, 5);
printf("\n");
print2(arr, 3, 5);
return 0;
}
✍数组指针原理图:
✍识别代码
int arr[5];//一维数组
int *parr1[10];//指针数组
int (*parr2)[10];//数组指针
int (*parr3[10])[5];//用来存放数组指针的数组
✍int (*parr3[10])[5];
🍎总结
- 个人认为指针的难度在于它在内存间的不断调换
- 要想学好指针,需要多画图,多尝试,多调试,看看它的内存是则么变化的
- 这一篇博客是c语言指针进阶的基础,后边的内容是这篇的衍生,将这里的内容理解后,后边会很好理解。