当前位置:   article > 正文

C++的数组和指针_c++指针数组

c++指针数组

目录

1、指针的5个要素

2、数组名的意义

3、指针和数组的存储的区别

4、指针作为返回值

5、二维数组

6、二重指针(指针的指针)

思考题和解析​​​​​​​


1、指针的5个要素

int num = 5;

int *ptr = #

变量的值num(5)

变量的地址&num(例如0x00006f23)

指针的值ptr(所指向的内存的地址,0x00006f23)

指针的地址&ptr(指针自己的存储地址)

指针指向的值*ptr(变量的值,即5)

通过指针修改所指向的变量的值:

*ptr = 100;

修改后:

变量的值num(100)

变量的地址&num(仍然是0x00006f23)

指针的值ptr(所指向的内存的地址,0x00006f23)

指针的地址&ptr(指针自己的存储地址)

指针指向的值*ptr(变量的值,即100)

2、数组名的意义

int a[10];

a是数组名,a的值是数组的首地址,例如a的值是0x00000001,那么a+1表示首地址加int大小的地址,即0x00000005,对a进行解引用才是数组首个元素的值,*a=a[0],*(a+1)=a[1].

&a是数组的指针,加一意味着数组首地址加上整个数组的长度(10个int型变量的长度)后的地址,即末尾元素的后一个元素的地址。

声明一个数组的指针:

int (*p)[10] = &a;

数组的指针跟二维数组的关联,下面会说到。 

3、指针和数组的存储的区别

看下面一段代码,思考问题。

1.四个指针的存储的空间在哪里?它们的值(所指向内存的地址)相等吗?

2.初始化的对象是什么?

3.字符串Hello World是常量吗? 

  1. int main()
  2. {
  3. char p1[] = "Hello World!";
  4. char p2[] = "Hello World!";
  5. //在栈上创建两个数组,分别存放字符串,首地址不一样
  6. if(p1 == p2) {
  7. } else {
  8. }
  9. char *p3 = "Hello World!";
  10. char *p4 = "Hello World!";
  11. //在栈上创建两个指针,分别指向存储在静态数据区的字符串,地址一样
  12. if(p3 == p4) {
  13. } else {
  14. }
  15. }

【1.存储的空间在哪】

第一种存储在栈上,第二种存储在静态数据区,p1和p2的值不相等,p3和p4的值相等。

【2初始化的对象是什么】

第一种初始化数组对象,第二种初始化指针对象。

【3.Hello World字符串是常量吗】

第一种不是常量,而是存储在数组中的局部变量,随着函数的返回就会被销毁,第二种是字符串常量,存储在静态数据区。事实上,第二种初始化的正确写法是 const char *p = "hello",将常量字符串的地址赋给指向char常量的指针。

《c和指针》上有一段:指针和数组并不是相等的,当声明一个数组时,它同时也分配了一段内存空间,用于存储数组元素,但当声明一个指针时,它只分配了用于容纳指针的空间(32位中4个字节的大小)。

p1、p2、p3和p4都具有指针值,都可以进行间接访问(解引用)和下标引用操作。但是它们还是存在区别和联系:

1. char p[] = “Hello World” 的意义是在栈上创建数组,数组直接存放Hello World字符串,数组名p代表这段内存的首地址,是一个常量,p++操作是错误的!而char * p = "Hello World"的意义是在栈上创建指针,指向存储在静态数据区的字符串,指针p是一个指针变量,p++操作是正确的!

2. 当一个数组名作为函数参数时,数组名等同于指向数组第一个元素的指针,所以此时传递给函数的是指针的拷贝,指针作为形参和数组名作为形参的效果是一样的。

4、指针作为返回值

考虑下面的例子:

  1. char *ptr1() {
  2. char p[] = "hello";
  3. return p;
  4. }
  5. char *ptr2() {
  6. char *p = "hello";
  7. return p;
  8. }
  9. int main() {
  10. char *p1 = ptr1();
  11. cout << p1 << endl; //输出乱码,而且每次输出都不一样
  12. char *p2 = ptr2();
  13. cout << p2 << endl; //正确的输出字符串
  14. }

p2可以正确的输出hello字符串,而每次运行时,p1都输出一个新的随机的乱码。

原因在于,ptr1()函数在栈上申请一段内存存放一个数组p,数组中存放字符串hello,p是该段内存的首地址,函数返回后,栈空间被回收,该字符串也不复存在,因此输出的内容是未知的。ptr2()函数在静态数据区申请一段内存,存储字符串hello,在栈上创建指针p,指向该段静态数据区的首地址,函数返回后,虽然指针本身被销毁了,但是静态数据区内的资源未销毁,而且通过函数的返回,该静态数据区的首地址被返回给p2,因此可以正确的输出字符串。

5、二维数组

二维数组名同样代表数组首元素的地址,int a[3][5],a的类型为int(*)[5]不是char**,二维数组名等同于数组的指针。

二维数组名的本质:数组的指针,即指向一个数组的指针

int a[3][5]

(a+i) 代表是i行的首地址。

*(a+i)就表示i行首元素的地址。

*(a+i) + j  等于 a[i][j]元素地址。

*( *(a+i) + j) 等于 a[i][j]元素的值。

一维数组名做函数参数:会退化为指针

int func(char buf[60]) //60无作用

int func(char buf[])和int func(char *buf)的意义相同

二维数组名做函数参数:第一维的参数可以省略

int func(char a[10][30]) //10无作用,30确定其步长

int func(char array[][30])//和上一个效果相同

int func(char (*array)[30])//和上一个效果相同,数组指针

  1. void Test1(char a[10][30], int n)
  2. {
  3. for (int i = 0; i < n; i++)
  4. {
  5. cout << a[i] << " ";
  6. }
  7. cout << endl;
  8. }
  9. void Test2(char a[][30], int n)
  10. {
  11. for (int i = 0; i < n; i++)
  12. {
  13. cout << a[i] << " ";
  14. }
  15. cout << endl;
  16. }
  17. void Test3(char(*a)[30], int n)
  18. {
  19. int i = 0;
  20. for (i = 0; i < n; i++)
  21. {
  22. cout << a[i] << " ";
  23. }
  24. cout << endl;
  25. }
  26. int main()
  27. {
  28. char array[5][30] = { "tttt", "eeee", "ssss", "tttt", "11111" };
  29. Test1(array, 4);
  30. Test2(array, 4);
  31. Test3(array, 4);
  32. system("pause");
  33. return 0;
  34. }

运行结果

对于形参来说,数组和指针的意义是一样的,多维数组的本质实际上还是一维数组只不过元素也是数组。

6、二重指针(指针的指针)

 二重指针的用法

(1)二重指针指向指针的地址

(2)二重指针指向指针数组的首地址

  1. int main()
  2. {
  3. const char *str[] = { "abcde", "aqw", "ulk" }; //指针数组
  4. char **p = const_cast<char **>(str); //不可以直接定义 **p = { "abcde", "aqw", "ulk" }; 指针数组指针
  5. cout << "sizeof(str): " << sizeof(str) << endl;
  6. cout << "sizeof(p): " << sizeof(p) << endl;
  7. cout << "sizeof(str[0]): " << sizeof(str[0]) << endl;
  8. for (int i = 0; i < sizeof(str) / sizeof(str[0]); i++)
  9. {
  10. cout << p[i] << endl; //输出一行数据
  11. }
  12. system("pause");
  13. return 0;
  14. }

运行结果:

思考题和解析

若有函数声明void f(char ** p),则使得函数调用f(var)不正确的var定义是?

A char var[10][10]

B char *var[10]

C void *var = NULL

D char *v = NULL, **var = &v

解析:

A. char var[10][10]; var的类型是 char (*)[10],传参后var的类型是char **

B. char *var[10]; var数组是存放char *类型的数组,数组名var是数组var元素的首地址,所以传参后var的类型是char **

C. void * 是定义没有指针类型的指针,void *可以指向任何类型的数据,但是不能转换成多重指针。

D. v是char*类型的,那么取v的地址肯定是char**类型的,所以var是char**类型的。

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/代码吟游诗人2/article/detail/63150
推荐阅读
相关标签
  

闽ICP备14008679号