❀❀❀ 文章由@不准备秃的大伟原创 ❀❀❀
♪♪♪ 若有转载,请联系博主哦~ ♪♪♪
❤❤❤ 致力学好编程的宝藏博主,代码兴国!❤❤❤
许久不见,甚是想念,本大忙人已经很久没有更新博客了,我想大概我的粉丝们早已按耐不住了吧(假)!好的啊,今天的话继续我们仍未结束的指针。
在上一篇有关指针的文章中我们谈论了有关野指针,assert断言以及与指针有关的计算。还没看过的小伙伴们可以戳戳这里传送哦~ -----> 指针 (Part two)
那么今天的话给大伙们介绍一下几种指针类型:字符指针,指针数组,数组指针和函数指针(当然最基础的指针变量大家都会的吧~) 什么,不会?那不赶紧戳一戳这里------> 指针 (Part one)
嗯哼,好的,接下来开始今天的正题:
我们既然有了整形指针,那么没有字符指针是不是说不过去?整形指针是int*,那么字符指针不就是char*吗?
好的,字符指针结束了。
...........................................................
大家都知道我的尿性吧?我说结束了不是结束,而屏幕前的你说结束才是结束,所以,实不相瞒,想要个赞(✿◡‿◡)
这时候问题就出来了,我们用字符指针存个 'a' 'C' 都是没有什么问题的吧,但 ? 字符串呢?存放的是整个字符串吗?还是只存首元素?还是存放的是首元素的地址?
如下面一段代码:
int main()
{
const char* pstr = "hello world!";//pstr里面到底存的是什么
printf("%s\n", pstr);
return 0;
}
在我们运行过后发现,打印的是整个hello world! ,那么我们的pstr存放的就是整个字符串。
—————— 对吗?
仔细考虑的同学就会发现疑点,“ 既然我用char str[]就可以存放一个字符串,那么char* 还有必要存在吗? ” 是的,我们这么仔细一想就发现,char*存放的才不是元素呢?是地址!是这个字符串的首元素的地址!但这时又有同学有疑惑了“既然存的是地址,那为什么还能打印出整个字符串呢?” 诶,好问题,这就要联系到我们的内存问题了,这部分博主以后会在博客里谈到,这里就简单给大家解释一下:
我们计算机中任何数据的存储都会占用一定的空间,而每一部分的空间都有自己的独自的地址,我们可以通过地址来寻找到这个空间存放的值。这和数组传参本质是一个道理,我们同样可以通过一个数组的首元素地址来找到数组后面的内容。
有意思吧?接下来看一个更有意思的代码:
#include
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;
}
怎么样,汗流浃背了?这其实没什么,记住我们数组传参的本质是地址,所以我们两个if比较的就是地址。所以答案是....?
对,答案是 not same和same。博主上面也讲到了吧?模拟实现二维数那里。我们创建的数组空间是不连续的,所以str1[] 和 str2[] 指向的是两块不同的空间,虽然他们的内容一样,但是我们if比较的是地址啊?所以是not same;而我们给字符指针str3和字符指针str4定义的是同一个内容(常量字符串), 而在C/C++中会把常量放到一块独立的空间里(常量区),这也就说明,我们的str3和str4指向的是同一块空间,所以是same。
诶,在开始前我先问大家一个问题,指针数组是指针还是数组?<(* ̄▽ ̄*)/ 我们其实可以类比一下:整形指针是存放整形的指针,字符指针是存放字符的指针,那么指针数组是存放指针的数组。即:指针数组的每个元素都是⽤来存放地址(指针)的。
那我们一般定义一个数组是怎么定义的?如存放整形的数组:int arr[10] = {0},每个元素存放的是整形,对吧? 那么同样的,存放指针的数组我们一般就这么定义:int *arr[10] = {0}; 每一个元素存放的是int*,即指针(地址)。
诶,但是这个时候我想到了一个很好玩的东西,既然我们可以定义个一维的指针数组,那可不可以用指针数组模拟实现个二维数组呢?
答案是可以的(不然博主也不会提出这个问题了对吧?)
博主有个思路:先创建普通的一维数组,在通过指针数组将一维数组放进去,即通过寻找每一个一维数组的首元素地址再往后找各个元素。代码实现如下:
#include
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数组中
int* parr[3] = { arr1, arr2, arr3 };
int i = 0;
int j = 0;
for (i = 0; i < 3; i++)
{
for (j = 0; j < 5; j++)
{
printf("%d ", parr[i][j]);
}
printf("\n");
}
return 0;
}
答案如下:
是不是很容易理解?我们这样就通过指针数组模拟实现了一个二位数组,但是!但是!但是!上述的代码模拟出⼆维数组的效果,实际上并⾮完全是⼆维数组,因为每⼀⾏并⾮是连续的(每一个一维数组向内存申请的空间是不连续的)。
指针数组的知识大概就到这里了,怎么样,是不是没有觉得很难?
那博主把铁汁们当一次傻子,数组指针内存放的是什么? 啊对对对,是指针,看来铁汁们有好好看上面的内容,博主很是欣慰。o(^▽^)o
那 int *p1[10]; int (*p2)[10]; 这两个哪个是数组指针?“不就是第二个吗?第一个不是指针数组?” 嗯嗯嗯,好好好,看到铁汁们这么快反应过来真好,哈哈。是的,我们将指针数组的变量名与*括起来就是表达的数组指针。
原理呢?不懂得可以听博主解释一下哦~:
解释:p先和*结合,说明p是⼀个指针变量变量,然后指着指向的是⼀个⼤⼩为10个整型的数组。所以 p是⼀个指针,指向⼀个数组,叫 数组指针。
指针数组可以存放多个指针,那么数组指针有什么用呢?既然存在了,怎么会没有用呢?就如同现在的你我可能还没有发觉自己的价值,但是如果你我是无价值的,上帝怎么可能会将我们放到人间呢?对吧,所以大家要对自己有信心!加油!
呃哼,扯远了,我们继续:如果要存放个数组的地址,就得存放在数组指针变量中,如下:
int(*p)[10] = &arr;
我们调试也能看到 &arr 和 p 的类型是完全⼀致的:
既然把数组指针学了,接下来二维数组的传参本质:
先给结论:arr[i] = *(arr+i) arr[i][j] = *(*(arr+i)+j)
那我们以前是怎么给函数传二维数组的呢?
void test(int a[3][5], int i, int j);//函数申明
test(arr, 3, 5);//main函数内部的传址和传值
⾸先我们再次理解⼀下⼆维数组,⼆维数组起始可以看做是每个元素是⼀维数组的数组,也就是⼆维 数组的每个元素是⼀个⼀维数组。那么⼆维数组的⾸元素就是第⼀⾏,是个⼀维数组。
而现在我们学了数组指针,我们就有新的玩法了:
根据数组名是数组⾸元素的地址这个规则,⼆维数组的数组名表⽰的就是第⼀⾏的地址,是⼀ 维数组的地址。根据上⾯的例⼦,第⼀⾏的⼀维数组的类型就是 int [5] ,所以第⼀⾏的地址的类 型就是数组指针类型 int(*)[5] 。那就意味着⼆维数组传参本质上也是传递了地址,传递的是第⼀ ⾏这个⼀维数组的地址,那么形参也是可以写成指针形式的。
所以我们可以这么写:
void test(int (*p)[5], int r, int c);//函数申明
test(arr, 3, 5);//main函数内部的传址和传值
总结:⼆维数组传参,形参的部分可以写成数组,也可以写成指针形式。
之前博主说过,任何数据都是有地址的,那,函数也包括在这个 ‘数据’ 里面吗?我们可以做个测试:
#include
void test()
{
printf("hehe\n");
}
int main()
{
printf("test: %p\n", test);
printf("&test: %p\n", &test);
return 0;
}
我们可以看到确实打印出来了地址,所以函数是有地址的,函数名就是函数的地址,当然也可以通过 &函数名 的⽅式获得函数的地址。
如果我们要将函数的地址存放起来,就得创建函数指针变量咯,函数指针变量的写法其实和数组指针 ⾮常类似。如下:
void test()
{
printf("hehe\n");
}
void (*pf1)() = &test;
void (*pf2)()= test;
int Add(int x, int y)
{
return x+y;
}
int(*pf3)(int, int) = Add;
int(*pf3)(int x, int y) = &Add;
给大家提供两段很有意思的代码,大家私下可以仔细思考思考:
(*(void (*)())0)();
void (*signal(int , void(*)(int)))(int);
OK,那么今天的任务也就到此为止了,下一篇part four是指针的最后一篇了,希望大家继续多多支持大伟,加油!