数组和指针

KeyPoint:

  • 数组和指针两者的关系如何?
  • 数组也有迭代器,比起vector迭代器有哪些不同?
  • 数组长度计算的几种方法?


1.数组与指针的关系

  • 在编译器层面,数组就是指针
    •  可以通过取数组元素的地址符来获得数组的元素
      • int arr[] = {1,2,3};
      • int *p = &arr[0];        
    • 但是更加一般的做法直接使用数组名字来赋值给指针
      • int *p2 = arr;    
      • 上面的表达式就是表示指针p2直接指向的是arr首元素的地址
  • 在很多情况下对于数组的操作实际上就是对指针的操作
    • auto推断为指针而非数组
      • int arr[] = {1,2,3};
      • auto a2(arr);  ==>auto a2(&arr[0]);
      • a2 = 10;      //err
      • 如下图:编译器会将其定义为指针
      •  
    •   需要注意的地方使用decltype的时候不会发生转成指针的情况
      •     
      • 这个会将其转换成数组,而不是指针

2.指针就数组的迭代器
数组的迭代器

  • 指针就是数组的迭代器
    • 支持类似于vector与string迭代器的运算
    •  指针指向的首地址就是首个元素的地址,尾地址是数组最后一个元素的下一个位置
      • int arr[] = {1,2,3,4,5};
      • 尾地址就是 arr[5]; 千万不要对其进行读取或者赋值,会造成不可估量的error  
      • 编译的时候是可以通过,但是使用中会导致崩溃的情况 

标准库函数begin和end (C++11)
  •  为什么要引入begin和end
    • 为了避免使用尾后指针带来错误
    • 主要使得指针使用更加安全和简单
  • 使用方法
    • 功能与vector同名函数类似
    • 但是类型不同,vector是对应的iterator,而数组类型的begin和end是对应的指针类型
      • int arr[] = {1,2,3};
      • int *beg = begin(arr);
      • int *en = end(arr);  
  •  注意的地方
    • 尾后指针不能执行解引用和递增操作
      • 因为其已经是数组最后一位的下一位了
指针运算
 
  • 指针运算就如同string 或者vector 迭代器的运算,如上图
  • 数组大小计算 end 和begin
    • auto n = end(arr) - begin(arr);
    • n的类型是ptrdiff_t类型 
  • 两个指针的比较
    • 针对数组的时候可以比较指向同一个数组元素或者尾后元素指针
    • 针对不同数组的时候不可以比较指针

解引用和指针运算的交互  
  •  指针加上一个整数所得的结果还是一个指针
    • int arr[] = {1,2,3}
    • int a = *(arr + 2);
    • int b = *arr + 2;
  • 上述的过程中解引用与圆括号的位置关系
下标和指针
  • 其实数组的名字就是一个指向数组首元素的指针
    • int arr[] = {1,2,3,4,5};
    • int a = arr[2];
    • int *p = ia;
    • a = *(p+2);    
  • 下标的使用可以是使用在指针指向的数组元素
    •  下标的使用与string和vector中是相似
    • 如果是数组类型是内置的类型,下标可以是有符号类型   



实例练习:
  1. auto 推断数组和指针的关系,decltype 推断关系
  2. 重写利用指针循环获取数组的值,尤其注意尾部指针的概念
  3. 利用begin 和end函数来循环一个数组
  4. 指针运算实例 ,begin 和end
  5. 解引用和指针交互运算(*)
  6. 下标的使用,注意有符号类型

     
     
  1. #include<iostream>
  2. #include<string>
  3. #include<vector>
  4. using std::string;
  5. using std::cin;
  6. using std::cout;
  7. using std::endl;
  8. using std::vector;
  9. using std::begin;
  10. using std::end;
  11. void main()
  12. {
  13. #pragma region auto 推断数组和指针的关系,decltype 推断关系
  14. //数组在某些时候就是指针
  15. int arr[] = { 1, 2, 3, 4, 5 };
  16. int *p = &arr[0]; //p就是指向数组首元素的指针
  17. int *p1 = arr; //这个是最常见的形式
  18. //如何证明数组在某些时候就是指针
  19. int arr1[] = { 1, 2, 3, 4, 5 };
  20. auto parr(arr1);
  21. // parr = 50; //err
  22. cout << endl;
  23. //decltype的使用
  24. decltype(arr1) p2;
  25. //p2 = parr; //err将指针赋值给数组
  26. p2[1] = 0;
  27. #pragma endregion
  28. #pragma region 重写利用指针循环获取数组的值,尤其注意尾部指针的概念
  29. int b_arr[] = { 1, 2, 3, 4, 5 ,6};
  30. int *b_p = b_arr;
  31. int *b_e = &b_arr[6]; //尾后指针,就是指向数组最优一个元素的下一个位置
  32. for (; b_p != b_e; b_p++)
  33. {
  34. cout << *b_p << endl;
  35. }
  36. //切记,不要试图对尾后元素进行操作
  37. /*b_arr[6] = 100;
  38. cout << "b_arr[6] = "<<b_arr[6] << endl;*/
  39. #pragma endregion
  40. #pragma region 利用begin end函数来循环一个数组
  41. int c_arr[] = { 1, 2, 3, 4, 5 };
  42. int *ben = std::begin(c_arr);
  43. int *en = std::end(c_arr); //*en 就相当于c_arr[5],是尾后指针,
  44. //切记,不要试图对尾后元素进行操作
  45. /**en = 100;
  46. cout << "*en = " << *en << endl;*/
  47. for (int *cur = ben; cur!=en; cur++)
  48. {
  49. cout << *cur << endl;
  50. }
  51. #pragma endregion
  52. #pragma region 利用begin end函数来计算数组长度
  53. int d_arr[] = { 1, 2, 3, 4, 5 };
  54. //计算数组长度C方法
  55. int d_arrLen = sizeof(d_arr) / sizeof(d_arr[0]);
  56. cout << "d_arrLenC = " << d_arrLen << endl;
  57. //计算数组长度C++方法
  58. auto d_arrLen2 = end(d_arr) - begin(d_arr);
  59. cout << "d_arrLenCPP = " << d_arrLen2 << endl;
  60. #pragma endregion 指针运算中的比较方法使用
  61. #pragma region 指针运算中的比较方法使用
  62. int e_arr[] = { 1, 2, 3, 4, 5 };
  63. int *e_p1 = e_arr;
  64. int *e_p2 = e_arr + 2;
  65. if (e_p1 > e_p2)
  66. {
  67. cout << *e_p1 << endl;
  68. }
  69. else
  70. {
  71. cout << *e_p2 << endl;
  72. }
  73. int e_arr2[] = { 2, 3, 4, 5 };
  74. int *e_p3 = e_arr2;
  75. //这个比较毫无意义可言,而且结果是错误的
  76. //针对不同数组的时候不可以比较指针
  77. if (e_p1 > e_p3)
  78. {
  79. cout << *e_p1 << endl;
  80. }
  81. else
  82. {
  83. cout << *e_p3 << endl;
  84. }
  85. #pragma endregion
  86. #pragma region 解引用和下标
  87. int f_arr[] = { 1, 2, 3, 4, 5 };
  88. //这里要注意解引用的指针所指向的位置关系
  89. int *f_p = f_arr;
  90. int f_a = *f_p + 2; // f_arr[0] +2
  91. int f_b = *(f_p + 2); // f_arr[2];
  92. cout << "*f_p + 2 = " << f_a << endl;
  93. cout << "*(f_p + 2)" << f_b << endl;
  94. int *f_p2 = f_arr + 3;
  95. //下标是可以为负数的,主要是针对内置类型是可以这样的,这个是与vector有点不同
  96. cout << " f_p2[-1] = "<<f_p2[-1] << endl;
  97. #pragma endregion
  98. system("pause");
  99. return;
  100. }

3.C风格字符串

简介
  • 并不是一种类型,而是一种约定写法
  • 该写法是中字符串数组最后一位必须是空字符结束
    • 最后一个字符后面跟着一个空字符('\0')
    • 一般使用指针来操作这些字符
  • 在C++尽可能不要使用C风格类型
C标准String函数
  • 需要注意的地方
    • 使用上面的函数是,要保证字符串是以空字符作为结束的    
字符串比较
  • C++(>  ,  <, ==)
  • C风格使用(>,<)
    • 实际上市用指向数组首元素的指针
  • strcmp 函数使用
    •     相等返回 0
    • 前者较大返回正值
    • 后者较大返回负值
  • 两个迭代器最差运算 it1 - it2
    • 返回值为difference_type类型,其为带符号的整数

字符串添加
  • C++(直接使用+)
  • C风格使用 strcat 和strcpy来添加合并字符串
    • 必须要要保证一个足够大的字符串以及末尾为空字符
    • 所以计算其存放字符串的大小非常重要
    • 这个也是非常容易出错的地方

 
  实例练习:
  1. C风格字符串函数使用注意要点
  2. 比较两种字符串比较的方法C++和C风格

3.字符串与旧代码的接口

string对象与C风格字符串混用
  • 允许使用空字符结束符的字符数组来初始化string对象
  • string加法运算中允许以空字符结束的字符作为运算对象
  • c_str函数的使用
    • string s("abc");
    • char *str = s;
    • const char *str = s.c_str()
使用数组初始化vector对象
  • 数组是不允许直接赋值或者初始化另外一个数组
  • 也不允许使用vector来初始化数组
  • 可以使用数组来来初始化vector对象

 
  实例练习:
  1. c_str 函数的使用
  2. 以上实例

        
        
  1. #include<iostream>
  2. #include<string>
  3. #include<vector>
  4. #define _CRT_SECURE_NO_WARNINGS
  5. using std::string;
  6. using std::cin;
  7. using std::cout;
  8. using std::endl;
  9. using std::vector;
  10. using std::begin;
  11. using std::end;
  12. void main()
  13. {
  14. #pragma region C风格字符串函数使用注意要点
  15. char a_s[] = { 'a', 'b', 'c' };
  16. char * a_ps = a_s;
  17. //这个时候会有一个严重的错误,因为字符串s并没有以\0结束,无法获得正确的长度
  18. while (*a_ps)
  19. {
  20. cout << *a_ps << endl;
  21. a_ps++;
  22. }
  23. cout << "len = " << strlen(a_s) << endl;
  24. //切记利用指针或者数组来构成字符串时,一定要记得在末尾加上\0
  25. char a_s2[] = { 'a', 'b', 'c' ,'\0'};
  26. char * a_ps2 = a_s2;
  27. while (*a_ps2)
  28. {
  29. cout << *a_ps2 << endl;
  30. a_ps2++;
  31. }
  32. cout << "len = " << strlen(a_s2) << endl;
  33. #pragma endregion
  34. #pragma region 字符串指针的比较
  35. char b_s1[] = "I am Wall.E";
  36. char b_s2[] = "I am Wall.F";
  37. //这个比较仅仅是比较两个指针的地址,并不是比较字符串
  38. if (b_s1 > b_s2)
  39. {
  40. cout << b_s1 << endl;
  41. }
  42. //正确的比较方法strcmp
  43. if (strcmp(b_s1, b_s2)>0)
  44. {
  45. cout << b_s1 << endl;
  46. }
  47. else
  48. {
  49. cout << b_s2 << endl;
  50. }
  51. #pragma endregion
  52. #pragma region 字符串指针的拼接
  53. char c_s1[] = "Hello";
  54. char c_s2[] = "Cpp";
  55. //相当于两个指针相加,并没有什么意义,所以以后指针的运算中一定小心
  56. //char c_s3[] = c_s1 + c_s2;
  57. //使用strcat尤其注意使用其长度的使用
  58. char c_s3[20] = {};
  59. strcat(c_s3, c_s1);
  60. strcat(c_s3, " ");
  61. strcat(c_s3, c_s2);
  62. cout << c_s3 << endl;
  63. #pragma endregion
  64. #pragma region c_str的使用
  65. string d_s = "we are family.";
  66. const char *d_ps = d_s.c_str();
  67. #pragma endregion
  68. #pragma region 使用数组初始化vector对象
  69. int e_arr[] = { 1, 2, 3, 4, 5, 6 };
  70. vector<int> e_v(begin(e_arr), end(e_arr));
  71. for (auto i : e_v)
  72. {
  73. cout << i << endl;
  74. }
  75. #pragma endregion
  76. system("pause");
  77. return;
  78. }





评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值