【问题标题】:Problem with writing elements of an array using the pointer使用指针写入数组元素的问题
【发布时间】:2019-12-10 07:50:27
【问题描述】:

第一个循环是完美的。二是不行。 “Z”有什么问题。 为什么循环不停止? 当我在表格中给出“Z”时,循环没有反应。

#include <iostream>
using namespace std;

int main()
{
    char tab[] { 'A', 'B', 'C', 'D', 'E', 'F', 'G',
                'H', 'I', 'J', 'K', 'L', 'M', 'N',
                'O', 'P', 'Q', 'R', 'S', 'T', 'U',
                'V', 'W', 'X', 'Y', 'Z' };

    char *wsk = tab;

    while(*wsk <= 'Y')
    {
        cout << *wsk << " ";
        wsk++;
    }
    cout << endl;

    wsk = tab;
    while(*wsk <= 'Z')
    {
        cout << *wsk << " ";
        wsk++;
    }
    cout << endl;
}

【问题讨论】:

  • 通常您会在列表末尾添加一个0 作为终止符,而不是任意的'Z'。此外,由于这是 C++,您可以使用 std::vectorstd::array 和常规迭代器,不需要 C 样式的数组。
  • 我的意思不是解决方案,而是意识到我离开了标签范围

标签: c++ loops pointers while-loop do-while


【解决方案1】:

'Z' 是数组的最后一个元素。在(应该是)最后一次迭代结束时,wsk 递增到指向数组的最后一个元素之外。在下一次迭代中,*wsk &lt;= 'Z' 通过越界指针间接访问,尝试访问不存在的对象,并且程序的行为未定义。

遍历整个数组的简单解决方案:

for(char c : tab)

使用指针的解决方案:

char* end = std::end(tab);
for(char* wsk = tab; wsk != end; wsk++)

您可以根据条件提前中断循环:

for(char c : tab) {
    std::cout << c;
    if (c >= 'Z')
        break;
}

如果你特别想要一个循环,当遇到某个值时结束,但该元素也必须被迭代,并且确定该值保证存在,并且由于某种原因无法知道数组的长度,那么你可以使用:

wsk = tab;
do {
    char c = *wsk++;
    std::cout << c;
} while(c < 'Z');

但请注意,如果数组中不存在该元素,这也会有 UB。

【讨论】:

  • wsk != end ==> wsk != end &amp;&amp; *wsk &lt;= 'Z'
  • @WhozCraig 可能;取决于OP的意图。
  • 同意。最初的while 条件很明确。
【解决方案2】:

在输出'Z' 后,您递增wsk 使其指向数组的末尾。然后它到达while (*wsk &lt;= 'Z'),因为*wsk 正在引用未定义的内存,所以任何事情都可能发生。

你需要while (*wsk &lt; 'Z'),或者也许

for ( ; ; )
  {
  cout << *wsk << " " ;
  if (*wsk >= 'Z') break ;
  wsk++ ;
  }

如果你想在退出循环之前输出'Z'

【讨论】:

  • 那么for( wsk = tab; true; ++wsk )更好
  • @Slava 甚至for( wsk = tab; ; ++wsk)
  • @scohe001 这只是口味问题,我发现将true 明确放在那里更具可读性。
  • @Slava:如果是口味问题,你为什么觉得你必须“纠正”我的代码?
  • @TonyK 的口味问题是将true 放入for 的条件部分或将其留空,结果相同。在您的代码中,您将初始化部分和增量部分留空,然后在代码中添加 2 行来执行此操作,这似乎很奇怪。例如代码int i = 0; for( ; ; ) { if( i &gt; 10 ) break; a[i] = 0; i++; } 看起来很难看,并提出了一个问题,为什么专门为其设计的for 部分没有被使用?。
【解决方案3】:

这是未定义的行为

while(*wsk <= 'Z')

您可能希望循环直到找到Z,打印Z,然后退出循环,对吗?但这不是这里发生的事情。你点击了Z,但*wsk &lt;= 'Z' 仍然是正确的,所以你会继续循环。

当您执行wsk++; 时,您现在超出了数组的范围!你刚刚踏入的这个广阔的开放记忆世界里有什么?谁知道!!

鉴于您想在此处执行的操作,您可以通过在数组中添加一个最大 char 值的终止字符来解决此问题:

char tab[] { 'A', 'B', 'C', 'D', 'E', 'F', 'G',
            'H', 'I', 'J', 'K', 'L', 'M', 'N',
            'O', 'P', 'Q', 'R', 'S', 'T', 'U',
            'V', 'W', 'X', 'Y', 'Z', 0x7f };
//                                  ^^^^^^
//Add the largest char to the end of the array

请注意,如果您的数组中的字符全部为 &lt;= 'Y',这也将防止您的第一个循环导致未定义的行为。我们在这里基本上保证无论内容如何,​​您都不会越界。

【讨论】:

    【解决方案4】:

    使用vectorrange for 循环:

    #include <iostream>
    #include<vector>
    using namespace std;
    
    int main()
    {
        vector<char> tab = { 'A', 'B', 'C', 'D', 'E', 'F', 'G',
                    'H', 'I', 'J', 'K', 'L', 'M', 'N',
                    'O', 'P', 'Q', 'R', 'S', 'T', 'U',
                    'V', 'W', 'X', 'Y', 'Z', 0};
    
    
        for(auto it:tab){
            cout<<it<<" ";
            if(it>'Z')
                break;
            }
        cout << endl;
    }
    

    Live

    【讨论】:

      【解决方案5】:

      和往常一样,问题是你选择了错误的循环。:)

      因此,在循环中,您将在数组之外继续迭代。

      这个条件

      *wsk <= 'Z'
      

      不会通过增加指针来阻止循环再进行一次迭代

      wsk++;
      

      在数组的最后一个元素之后访问内存。

      改用do-while loop

      这是一个演示程序

      #include <iostream>
      
      int main() 
      {
          char tab[] { 'A', 'B', 'C', 'D', 'E', 'F', 'G',
                      'H', 'I', 'J', 'K', 'L', 'M', 'N',
                      'O', 'P', 'Q', 'R', 'S', 'T', 'U',
                      'V', 'W', 'X', 'Y', 'Z' };
      
          for ( char c : tab )
          {
              const char *wsk = tab;
      
              do
              {
                  std::cout << *wsk << " ";
              } while ( *wsk++ != c );
      
              std::cout << '\n';
          }       
      
          return 0;
      }
      

      它的输出是

      A 
      A B 
      A B C 
      A B C D 
      A B C D E 
      A B C D E F 
      A B C D E F G 
      A B C D E F G H 
      A B C D E F G H I 
      A B C D E F G H I J 
      A B C D E F G H I J K 
      A B C D E F G H I J K L 
      A B C D E F G H I J K L M 
      A B C D E F G H I J K L M N 
      A B C D E F G H I J K L M N O 
      A B C D E F G H I J K L M N O P 
      A B C D E F G H I J K L M N O P Q 
      A B C D E F G H I J K L M N O P Q R 
      A B C D E F G H I J K L M N O P Q R S 
      A B C D E F G H I J K L M N O P Q R S T 
      A B C D E F G H I J K L M N O P Q R S T U 
      A B C D E F G H I J K L M N O P Q R S T U V 
      A B C D E F G H I J K L M N O P Q R S T U V W 
      A B C D E F G H I J K L M N O P Q R S T U V W X 
      A B C D E F G H I J K L M N O P Q R S T U V W X Y 
      A B C D E F G H I J K L M N O P Q R S T U V W X Y Z 
      

      【讨论】:

      • ...不是你做的,而与while( *wsk++ != c ) { ... 完全一样吗?我认为在此期间根本不需要做任何事情。您唯一的区别是您在 before 打印而不是之后递增。
      • @scohe001 不,它们是不同的。 do-while 循环输出包括 c 在内的所有字符。您的循环跳过序列中的第一个字符,因为在条件 while( *wsk++ != c ) 中,指针增加了。
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2021-10-30
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2018-11-14
      • 2016-07-02
      相关资源
      最近更新 更多