初识指针回顾:
1、指针就是个变量,用来存放地址,地址唯一标识一块内存空间。
2、指针的大小是固定的4/8个字节(32位平台/64位平台)。
3、指针是有类型,指针的类型决定了指针的±整数的步长,指针解引用操作的时候的权限。
4、指针的运算。
推薦網站:segmentfault
字符指针
在指针的类型中有一种指针类型为字符指针:char*
#define _CRT_SECURE_NO_WARNINGS 1
#include <stdio.h>
int main()
{
char arr[] = "abcdef";
char* pc = arr;
char* p = "abcdef";//是一个常量字符串
printf("%s\n", arr);
printf("%p\n", arr);
printf("%s\n", pc);
printf("%s\n", p);
printf("%p\n", p);
printf("%c\n", *p);
return 0;
}
输出如下:
指针数组
指针数组是数组,用来存放指针
指针数组的主要用法。
#define _CRT_SECURE_NO_WARNINGS 1
#include <stdio.h>
int main()
{
int arr[10] = { 0 };//整型数组
char ch[5] = { 0 };//字符数组
int* parr[4];//存放整型指针的数组-指针数组
char* pch[5];//存放字符指针的数组-指针数组
return 0;
}
#define _CRT_SECURE_NO_WARNINGS 1
#include <stdio.h>
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 };
int i = 0;
for (i = 0; i < 3; i++)
{
int j = 0;
for (j = 0; j < 5; j++)
{
printf("%d ", *(parr[i] + j));
}
printf("\n");
}
return 0;
}
输出:
int* arr1[10];//整型指针的数组
char* arr2[4];//一级字符指针的数组
char** arr3[5];//二级字符指针的数组
数组指针
数组指针的定义
数组指针是指针。
int arr[10]={1,2,3,4,5,6,7,8,9,10}
arr-首元素地址
&arr[0]-首元素地址
&arr-数组的地址
int (*p)[10]=&arr
解释:
int (*p)[10];
//解释:p先和 星 结合,说明p是一个指针变量,然后指着指向的是一个大小为10个整型的数组。所以p是一个指针,指向一个数组,叫数组指针。
//这里要注意:[]的优先级要高于 星 号的,所以必须加上()来保证p先和 星 结合。
例子:
#define _CRT_SECURE_NO_WARNINGS 1
#include <stdio.h>
int main()
{
char* arr[5];
char* (*pa)[5]=&arr;
int arr2[10] = { 0 };
int(*pa2)[10] = &arr2;
return 0;
}
例题:(方法一方法二不推荐使用)
#define _CRT_SECURE_NO_WARNINGS 1
#include <stdio.h>
int main()
{
int arr[10] = { 1,2,3,4,5,6,7,8,9,10 };
//int (*pa)[10] = &arr;
//int i = 0;
//for (i = 0; i < 10; i++)//方法一
//{
// printf("%d ",(*pa)[i]);
//}
//int(*pa)[10] = &arr;
//int i
//for (i = 0; i < 10; i++)//方法二
//{
// printf("%d ",*(*pa + i));//*pa==arr
//}
int *p=arr;//方法三
int i = 0;
for (i = 0; i < 10; i++)//方法一
{
printf("%d ",*(p+i));
}
return 0;
}
使用:
#define _CRT_SECURE_NO_WARNINGS 1
#include<stdio.h>
#include<Windows.h>
void print1(int arr[3][5], int x, int y)
{
int i = 0;
int j = 0;
for (i = 0; i < x; i++)
{
for (j = 0; j < y; j++)
{
printf("%d ", arr[i][j]);
}
printf("\n");
}
}
void print2(int(*p)[5], int x, int y)
{
int i = 0;
for (i = 0; i < x; i++)
{
int j = 0;
for (j = 0; j < y; j++)
{
printf("%d ", p[i][j]);
//printf("%d ", *(p[i] + j));
//printf("%d ", *(*(p + i)+j));
//printf("%d ", (*(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 } };
//print1(arr,3,5);//基本方法 arr-数组名-数组名就是首元素地址
print2(arr, 3, 5);
return 0;
}
使用2:
#define _CRT_SECURE_NO_WARNINGS 1
#include<stdio.h>
#include<Windows.h>
int main()
{
int arr[10] = { 1,2,3,4,5,6,7,8,9,10 };
int i = 0;
int *p = arr;
for (i = 0; i < 10; i++)
{
printf("%d ", p[i]);
printf("%d ", *(p + i));
printf("%d ", *(arr + i));
printf("%d ", arr[i]);//arr[i]==*(arr+i)==*(p+i)==p[i]
}
return 0;
}
指针和数组是两种不同的数据类型,但它们之间有一些相同和不同之处。
相同点:
+都可以用来访问内存中的数据;
+都可以通过指针算术运算或数组的索引操作来访问该数据;
+都具有传递参数和返回值等功能。
不同点:
+指针是一个变量,它存储了一个内存地址,而数组是一组相同数据类型的元素集合;
+指针可以指向任何数据类型的内存地址,而数组只能包含相同类型的元素;
+指针可以动态修改指向的内存地址,而数组的大小在编译时已经确定,不能动态修改;
+指针本身占用空间,而数组不占用额外空间,其大小仅取决于元素个数和类型大小。
总之,指针和数组都是非常重要的C语言特性,它们可以帮助我们更好地管理和使用内存。.
自行探索补充:
(&(*pa))[i]和&(*pa)[i]不一样。前者步长是整个数组,后者是一个元素。
(&(*pa))[i]和&(*pa)[i]是不同的表达式。
首先,&(pa)[i]表示的是指向pa
所指向的数组的第i
个元素的指针。pa
本身是一个指向数组首元素的指针,所以pa表示数组的首元素,(*pa)[i]表示数组的第i个元素,然后&(*pa)[i]表示该元素的地址。
而(&(*pa))[i]表示的是指向pa
所指向的指针所在内存地址处的数组的第i
个元素的指针。即将pa
指向的指针本身视为一个数组,其下标为0的元素的地址就是pa
指向的内存地址,所以&(*pa)就是pa
指向的内存地址,(&(*pa))[i]就是该地址后面的第i
个元素的地址。
因此,这两个表达式虽然都涉及到指针和数组,但其含义和计算方式是不同的。
int(*pa)[10] = &arr;
printf(“%p\n”, *pa);
printf(“%p\n”, pa);
在这段代码中,pa
是一个指向大小为10的数组的指针, &arr
是整个数组的地址。因为&arr
是一个指向数组arr
的指针,所以可以将&arr
赋值给指向数组的指针pa
。
在第一个printf
语句中,*pa
将解引用指针pa
指向的数组,因此表达式*pa
的值是数组的首个元素的地址。因为数组的元素的大小是sizeof(int)
,因此首个元素的地址也是该数组的地址。所以第一个printf
打印的是数组arr
的地址。
在第二个printf
语句中,我们直接打印指针pa
的值,这个值是指向数组arr
的地址,因此第二个printf
打印的就是数组arr
的地址。
值得注意的是,*pa
与pa
指向的内存位置不同,*pa
指向的是数组中第一个元素的地址,而pa
指向的是整个数组的地址。这两个指针指向的内存地址是不同的,尽管它们的值相同。
为什么定义一个int* p之后,p也能通过p[]来表示?
在C语言中,指针和数组在使用上是非常相似的,有时它们可以互换使用,这是因为数组的下标运算符[]可以被重载,可以被用于指针运算做下标。
指针p本身是一个地址值,p[]实际上等价于*(p + i),即取指针p所指向的内存地址加上下标i所表示的偏移量的值,然后再解引用得到该地址处的值。由于编译器在处理数组时,会将数组名先转换成指向数组首元素的指针,所以在使用数组下标运算符[]时,指针的使用方式可以与数组等价使用。因此,定义一个int* p后,p也能通过p[]来表示。
需要注意的是,这种方式只适用于已经申请了合法内存地址的指针,否则会出现未定义行为或者导致程序崩溃。同时,指针与数组的实际类型和内存布局等仍然有所区别,因此在某些特定情况下,应该明确区分指针和数组的使用方式。
int arr[5]; //arr是一个5个元素的整型数组
int * parr1[10]; //parr1是一个数组,数组有10个元素,每个元素的类型是int*,parr1是指针数组。
int (*parr2)[10]; //parr2是一个指针,该指针指向了一个数组,数组有10个元素,每个元素的类型是int.parr2是数组指针。
int (*parr3[10])[5]; //parr3是一个数组,该数组有10个元素,每个元素是一个数组指针。该数组指针指向的数组有5个元素,每个元素是int.