一、字符指针
通常我们使用字符指针来存放字符的地址:
#include <stdio.h>
int main()
{
char a = 'A';
char* pa = &a;
printf("%c", *pa);
return 0;
}
pa就是一个字符指针变量。
#include <stdio.h>
int main()
{
char* str = "abcdefgh";
printf("%s", str);
return 0;
}
注意的是此时是将字符串的第一个字符'a'的地址存入字符指针变量str中。
而且字符串"abcdefgh"是常量字符串,是不可以通过解引用来改变的,这种行为是未定义的。
常量字符串是存放在只读数据区的,所以两个相同的常量字符串所开辟的空间只有一块。
例题:
#include <stdio.h>
int main()
{
char str1[] = "hello bit.";
char str2[] = "hello bit.";
const char* str3 = "hello bit.";
const char* str4 = "hello bit.";
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;
}
两个字符数组在内存中开辟的空间是不同的(数组名是首元素地址,sizeof和&数组名除外),而常量字符串的空间是相通的。因为字符串在str1的时候已经有了,所以str2的时候只是改了指向,并没有重新在内存中开辟空间。
二、数组指针
数组指针是指向数组的指针。
#include <stdio.h>
int main()
{
int arr[10] = { 1,2,3,4,5,6,7,8,9,10 };
int(*p)[10] = &arr;
int i = 0;
for (i = 0; i < 10; i++)
{
printf("%d ", *((*p) + i));
}
return 0;
}
p就是一个数组指针,指向的数组有10个元素,每个元素为int。
数组指针一般是用来维护二维数组的。
#include <stdio.h>
void Print(int(*p)[3], int row, int col)
{
int i = 0;
for (i = 0; i < row; i++)
{
int j = 0;
for (j = 0; j < col; j++)
{
printf("%d ", *(*(p + i) + j));
}
printf("\n");
}
}
int main()
{
int arr[3][3] = { 1,2,3,4,5,6,7,8,9 };
Print(arr, 3, 3);
return 0;
}
像这样,arr为数组名,传数组名就是传数组首元素地址,二维数组的首元素是第一行的一维数组,所以传进去的是一维数组的地址,所以我们用一个一维数组指针来接收。
*(arr+i)是拿到了第一行数组的数组名,也就是第一行数组的首元素地址,就是1的地址,然后
*(*(arr+i)+j)就拿到了这一行的所有元素。
三、二级指针
我们知道,一个变量的地址我们可以用相对应类型的指针变量来接收,那么当然,指针变量也是有地址的,那么当接收时,就得用一个二级指针来接收,通常我们把接收一级指针变量地址的变量叫二级指针。
#include <stdio.h>
int main()
{
int a = 10;
int* pa = &a;
int** ppa = &pa;
printf("%d", **ppa);
return 0;
}
当然,二级指针不是这么用的,主要是通过二级指针来将函数内部和外界建立链接。在这里是为了表明概念。
以此类推,也就有三级、四级指针,按需创建就行。(套娃模式)