文章目录
- 指针
- 字符指针
- 实例一
- 实例二
- 指针数组
- 实例一
- 实例二
- 实例三
- 数组指针
- 实例一
- 实例二
- 实例三-看书呗
指针
1.指针是个变量,用来存放地址,地址将唯一标识一块内存空间
内存编号=地址=指针
2.指针的大小是固定的,32位平台是4个字节,64位平台是8个字节
字符指针
原文:
https://blog.csdn.net/m0_53558236/article/details/125949857
实例一
char* 类型的指针称为字符指针
int main()
{
char ch = 'w';
char *pc = &ch;//pc是指向一个字符变量
*pc = 'w';
return 0;
}
char* pc = &ch;//前面的表示pc是个指针变量,char表示pc指向的变量的类型是char类型
等价于:
char pc;
pc = &ch;
实例二
int main()
{
char* p = "hello world";
printf("%s", p);
return 0;
}
char* p = “hello world”;
特别容易让人以为是把字符串 hello world 放到字符指针 p 里
了,其实不是的。
"hello world"是一个常量字符串,存放在内存的常量区。
上面表达式的作用是:把常量字符串"hello world"的第一个字符h的地址赋值给p。
我们可以来测试一下是不是这样?
printf(“%c”, *p);
上面说p指向 hello world的首字母h的地址,那么对p解引用,*p就是h,我们来运行一下看是不是这样
可以看到,确实是这样的
其实
p指针是指向了hello world这个字符串,但它只是存了h的地址,指向了h就相当于指向了hello
world整个字符串,因为这个字符串是连续的。 所以我们要打印一个字符的时候,用printf(“%c”, p);用%c和p
如果我们要打印整个字符串,则用printf(“%s”, p);用%s和p
printf(“%c”, p); printf(“%s”, p);
写成%s的时候,后面“p”这里只提供一个地址就可以了。p里面存的是h的地址,打印时就从p里面存的h的地址开始打印整个字符串hello
world。 💡注意:
这里写一个p就可以了,不要写成p了。*p指的是一个字符h。写%s表示打印字符串,后面给一个地址就可以了;而%c表示只打印一个字符。
隐含的问题
其实这个写法char* p = “hello world”;不太好,有的编译器可能会报错。
因为"hello world"是一个常量字符串,存放在内存的常量区是不允许改动的。而前面的char* p是不受限制的,一旦p指针重新改动,即后面的不允许改,但前面的有随意改动,程序就会报错
比如说我们来改一下p,运行时不会报错,不过一直也不会给出打印的结果,但调试一下就会显示错误
前面讲的时候,常量字符串用的是"hello world",这里我截屏上写的是"hello bit",一个意思,改动的是p)可以看到确实不行。
我们可以用到const,用它来修饰p,即指针指向的内容就不能被修改了,一旦我们修改了p,编译器就会报错提醒,如下图
所以如果写常量字符串,我们要有一个指针指向的话,前面最好加一个const修饰,这样比较合理。
指针数组
参考文章:
https://blog.csdn.net/m0_53558236/article/details/127057577
整型数组:存放整形的数组
int arr[10]={1,2,3,4,5,6,7,8,9,10};
arr是一个数组,数组有10个元素,每个元素是整形。
字符数组:存放字符的数组
char ch[5]={‘a’,‘b’,‘c’,‘d’,‘e’};
ch是一个数组,数组有5个元素,每个元素是字符类型。
指针数组是一个存放指针的数组。
char* arr[5];//arr是存放字符指针的数组
int* arr2[4];//arr2是存放整形指针的数组
实例一
int a = 10;
int b = 20;
int c = 30;
int d = 40;
int* arr2[4] = {&a, &b, &c, &d};//arr2就是整型指针的数组
我们知道,这时,&a, &b, &c, &d的类型都是int*
内存布局如下:
接下来创建了arr2数组,数组里面有4个元素,元素类型是int*,这个数组的空间是连续的
int* arr2[4] = {&a, &b, &c, &d};意味着取地址a,指向的a的地址,取地址b,指向b的地址,以此类推
那么如果我们拿到了arr2数组,我们就能把a,b,c,d的值打印出来,具体操作如下:
当我们通过arr2[i],就能找到下标为i的元素,对arr2[i]解引用,即arr2[i],就能找到arr2[i]对应指向的内存的值。比如:arr2[1],就是&b,对arr2[1]解引用arr2[1],就能得到&b指向的内存b的值20了。
用个循环即可打印出10,20,30,40了。
int i = 0;
for (i = 0; i < 4; i++)
{
printf("%d ", *(arr2[i]));
}
实例二
我们给出
int main()
{
int arr1[5] = { 1,2,3,4,5 };
int arr2[5] = { 2,3,4,5,6 };
int arr3[5] = { 3,4,5,6,7 };
int* parr[3] = { 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;
}
上面的arr1[ ],arr2[ ],arr3[ ]代表整形数组,parr[ ]代表整形指针数组
我们知道,数组名就是首元素的地址
如代码int* parr[] = { arr1, arr2, arr3 };中arr1就代表arr1[ ]数组首元素“1”的地址
上面代码对应的内存布局如下图:
那么我们如果得到了parr数组,那么我们就能依次的打印出12345 23456 34567 45678了
通过parr下标为0的元素,拿到arr1的起始地址;通过parr下标为1的元素,拿到arr2的起始地址,以此类推。
如果还是难以理解,我们也可以这样
parr为指针数组的首元素地址,parr+i,指向了数组中下标为 i 的元素,(parr+i)表示拿到了 指针数组 parr 下标为 i
的元素,假设 i =1,就意味着拿到了arr2这个元素,arr2为数组名,代表数组arr2的首元素地址。arr2+j
意味着指向了arr2数组中下标为 j 的元素,(arr2+j)意味着拿到了下标为 j 的元素。所以
((parr+i)+j)相当于访问了arr1,arr2,arr3三个数组中的所有元素。
parr[i] == *(parr+i)
parr[i][j] == *(parr[i]+j)== *(*(parr+i)+j)==(*(parr+i))[j]
❗注意:这里看起来像是二维数组或二级指针,其实不是的,这里用的是其实是指针数组,不要混淆了。二级指针是用来存放一级指针变量的地址的,和二维数组也没有关系。
我们来看看运行结果
实例三
我们给出
char* arr[5] = {neijvbucun"Aaaa", "Bbbb", "Cccc", "Dddd", "Eeee"};
arr是个含有5个元素的数组,每个元素的类型是char*,我们用5个常量字符串去初始化是可以的,相当于arr中存放的依次是首字符A,B,C,D,E的地址。
因为里面放的都是常量字符串,每个元素都是不允许改的,所以我们在char*前面加上const,这样会更好一些。
const char* arr[5] = {"Aaaa", "Bbbb", "Cccc", "Dddd", "Eeee"};
内存布局如下图
然后我们可以打印这些字符串
int main()
{
const char* arr[5] = { "Aaaa", "Bbbb", "Cccc", "Dddd", "Eeee" };
int i = 0;
for (i = 0; i < 5; i++)
{
printf("%s\n", arr[i]);
}
printf("%s\n", arr[2]);
return 0;
}
运行一下:
数组指针
此部分原文
https://blog.csdn.net/bingbing_bang/article/details/123290615
什么是数组指针?数组指针是数组吗?
数组指针并不是数组,而是一个指针,存放的是数组的地址,是能够指向数组的指针
表达形式:int (*p)[10]
p是一个指针,指向的是一个数组的地址,数组有10个元素,每个元素是int类型
注意:不要写成 int p [10] 这个表达式并不是数组指针,因为号的优先级低于[ ]
所以p先与[10]结合,构成数组,然后数组有10个元素,每个元素是int*类型,代表指针数组。
那数组指针该如何用呢?
将数组arr的地址取出来,放到数组指针p中。
再次重申一遍数组名和 &数组名的区别
通常情况下,数组名代表数组首元素的地址,但是有两个例外
1.sizeof(数组名),这里的数组名代表整个数组,计算的是整个数组的大小
2.&数组名,这里数组名表示的是整个数组,取出的是整个数组的地址。
sizeof(arr)和sizeof(arr[0]),计算的分别是数组的大小和数组首元素的大小,但是这里打印出来的数组名和&数组名怎么一样啊,不是代表的含义不同吗?
这两个地址虽然一样但是意义还确实不同,一个代表首元素的地址,一个代表整个数组的地址,数组有10个元素,也有起始位置的地址,因此显示的也是首元素的地址。但不代表&arr和arr含义一样。
举一个简单的例子进行验证,令arr+1 ,&arr+1 ,分别打印出来此时的地址,如果是首元素地址,那跳过的应该是4个字节,如果是数组的地址,那跳过的是整个数组的大小,也就是40
数组指针怎么用?
实例一
两个函数都能完成数组内容的打印,可是print2函数理解和使用起来更加复杂,并没有print1函数直观,其原理一样,但是print2函数对其进行了复杂化,先解引用找到数组名,再通过数组名找到元素地址,再对其进行解引用找到元素内容,太冗余,明明可以直接传数组名进行操作,多此一举。
确实,数组指针一般不会用到一维数组上
实例二
打印二维数组的内容
在这里用数组指针接收,对其进行了降维处理,将二维数组变为一维数组进行处理,更容易理解。
实例三-看书呗
![在这里插入图片描述](https://img-blog.csdnimg.cn/8eaf308d7fe547269eae160a44007f00.jpeg