int main()
{
char ch = 'w';
char* pc = &ch;// pc就是字符指针
char* p = "abcdef";// 把字符串首元素地址放在p中
*p = 'w';
return 0;
}
表达式的值是首元素的地址
但是这段代码运行起来会崩掉,调试看一下
因为这里的 “abcdef” 是常量字符串,不能被修改
int main()
{
char arr[] = "abcdef";
char* p = arr; // p指向的是arr数组首元素地址,arr数组是可以修改的
*p = 'w';
printf("%s\n", arr);// wbcdef
return 0;
}
这里就可以很好的运行,因为p指向的是arr数组首元素地址,arr数组是可以修改的
字符指针不仅仅可以指向字符,还可以指向字符串,但其实指向的还是字符串首字符,但是可以顺藤摸瓜找到整个字符串的字符,指向数组也是一样的
看一道例题
int main()
{
char str1[] = "hello programming.";
char str2[] = "hello programming.";
const char* str3 = "hello programming.";
const char* str4 = "hello programming.";
if (str1 == str2)
printf("str1 and str2 are same\n");
else
printf("str1 and str2 are not same\n");
if(str3 == str4)
printf("str3 and str4 are same\n");
else
printf("str3 and str4 are not same\n");
return 0;
}
这里str3和str4指向的是同一个常量字符串。C/C++会把常量字符串存储到单独的一个内存区域,当几个指针指向同一个字符串的时候,他们实际会指向同一块内存。但是用相同的常量字符串去初始化不同的数组的时候就会开辟出不同的内存块。所以str1和str2不同,str3和str4相同。
类比一下:
字符数组 ---- 存放字符的数组
char arr1[10];
整型数组 ---- 存放整型的数组
int arr2[5];
指针数组 ---- 存放的就是指针
eg:存放字符指针的数组 ---- 字符指针数组
char* arr3[5];
eg:存放整型指针的数组 ---- 整形指针数组
int* arr4[6];
举个栗子:
eg1:
int main()
{
char* arr[] = { "abcdef","hehehe","666" };
int i = 0;
for (i = 0; i < 3; i++)
{
printf("%s\n", arr[i]);
}
return 0;
}
int main()
{
int arr1[] = { 1,2,3,4,5 };
int arr2[] = { 2,3,4,5,6 };
int arr3[] = { 3,4,5,6,7 };
//arr是一个存放整型指针的数组
int* arr[] = { arr1,arr2,arr3 };
int i = 0;
for (i = 0; i < 3; i++) //行
{
int j = 0;
for (j = 0; j < 5; j++) //列
{
printf("%d ", *(arr[i] + j));
// printf("%d ", arr[i][j]);
}
printf("\n");
}
return 0;
}
类比一下:
整型指针 ---- 指向整型的指针
int a = 10;
int* p = &a;
字符指针 ---- 指向字符的指针
char ch = ’w‘;
char* pc = &ch;
数组指针 ---- 指向数组的指针 ---- 存放的是数组的地址
int arr[10];
int ( * pa)[10] = &arr; 取出的是数组的地址
char arr[10];
char ( * pc)[10] = &arr;
int* arr[5];
int * (*p)[5] = &arr;
数组名绝大部分情况下是数组首元素的地址
有两个例外:1. sizeof (数组名)------ sizeof 内部单独放一个数组名的时候,数组名表示的是整个数组,计算得到的是数组的总大小
2. &arr ------ 这里的数组名表示整个数组,取出的是整个数组的地址,从地址值的的角度来讲,和数组首元素的地址是一样的,但是意义不一样
int main()
{
int arr[10] = { 0 };
printf("%p\n", sizeof(arr));
printf("%p\n", arr);
printf("%p\n", &arr[0]);
printf("%p\n", &arr);
return 0;
int main()
{
int arr[10] = { 0 };
//printf("%p\n", sizeof(arr));
printf("%p\n", arr);//int*
printf("%p\n", arr+1);//4
printf("%p\n", &arr[0]);//int*
printf("%p\n", &arr[0]+1);//4
printf("%p\n", &arr);//int(*)[10]
printf("%p\n", &arr+1);//40
int(*p)[10] = &arr;//p是一个数组指针
//int(*)[10]
return 0;
}
根据第一段代码我们发现,其实 &arr 和 arr,虽然值是一样的,但是意义应该不一样的
实际上: &arr 表示的是数组的地址,而不是数组首元素的地址(细品)
第二段代码中 &arr 的类型是:int (*)[10],是一种数组指针类型,数组指针的地址+1,跳过整个数组大小, 所以&arr+1 相对于&arr 的差值是40
我们直接上代码和注释(请细品)
int main()
{
int arr[10] = { 1,2,3,4,5,6,7,8,9,10 };
int i = 0;
int sz = sizeof(arr) / sizeof(arr[0]);
//使用指针来访问
//int* p = arr;
//for (i = 0; i < sz; i++)
//{
// printf("%d ", *(p + i));
//}
int(*p)[10] = &arr;
//p ---- &arr
//*p ---- *&arr
//*p ---- arr
for (i = 0; i < sz; i++)
{
printf("%d ", *((*p) + i));
}
return 0;
}
//一维数组传参,形参是数组
void print(int arr[10], int sz)
{
int i = 0;
for (i = 0; i < sz; i++)
{
printf("%d ", arr[i]);
}
printf("\n");
}
//一维数组传参,形参是指针
void print(int *arr, int sz)
{
int i = 0;
for (i = 0; i < sz; i++)
{
//printf("%d ", arr[i]);
printf("%d ", *(arr+i));
}
printf("\n");
}
int main()
{
int arr[10] = { 1,2,3,4,5,6,7,8,9,10 };
int sz = sizeof(arr) / sizeof(arr[0]);
print(arr, sz);
return 0;
}
void print(int arr[3][5], int r, int c)
{
int i = 0;
for (i = 0; i < r; i++)
{
int j = 0;
for (j = 0; j < c; j++)
{
printf("%d ",arr[i][j]);
}
printf("\n");
}
}
void print(int(*arr)[5], int r, int c)
{
int i = 0;
for (i = 0; i < r; i++)
{
int j = 0;
for (j = 0; j < c; j++)
{
printf("%d ", *(*(arr + i) + j));//arr[i]
}
printf("\n");
}
}
int main()
{
int arr[3][5] = { 1,2,3,4,5, 2,3,4,5,6, 3,4,5,6,7 };
//二维数组的数组名,也表示首元素地址
//二维数组的首元素是第一行
//首元素的地址就是第一行的地址,是一个一维数组的地址
print(arr, 3, 5);
return 0;
}
希望大家能够理解呀
总结
以上就是 指针的进阶【上篇】 内容啦
本文章所在【C语言知识篇】专栏,感兴趣的烙铁可以订阅本专栏哦
欲知后事如何,请听下篇分解喽
小的会继续学习,继续努力带来更好的作品
创作写文不易,还多请各位大佬uu们多多支持哦