【问题标题】:Iterate elements of array using pointer使用指针迭代数组元素
【发布时间】:2014-04-22 19:50:20
【问题描述】:

我尝试执行代码:

char* m[3] = {"123", "456", "789"};
for(char* st=*m; st!=0; st=*(m+1))
{
    cout <<st;
} 

但它挂断并打印:123456456456...

【问题讨论】:

  • 不要使用非常量 char * 指向不可修改的字符串文字。
  • st=*(m+1) - 因为第二次迭代你总是指向第二个字符串...

标签: c++ arrays pointers iterator


【解决方案1】:

使用您在此处提供的代码是一种方法:

const char* m[3]={"123","456","789"};
const unsigned int element_count = sizeof(m) / sizeof(m[0]);
//not a nice to have sizeof here, but i used this to keep the code
// consistent with the code provided in the question

for( const char** st = m; st!= (m + element_count) ; st ++ )
{
    cout << *st;
}

如您所见,要遍历 char* 元素数组,您需要使用指向 char* 的指针,因此迭代变量 st 的类型为 char **

您的代码是一个无限循环,因为您将 st 分配给了永远不等于 0 的 *(m+1),实际上它每次都是第二个元素。

但是有更安全的方法来执行此操作,例如使用std::vector

std::vector<std::string> m = {"123", "456", "789"};
for (auto& st : m) 
    std::cout << st;
//or:
for(std::vector<std::string>::iterator i = m.begin(),e = m.end();i != e;i++)
    std::cout << *i;
//or:
for(std::size_t i = 0;i < m.size() ;i++)
    std::cout << m[i];

【讨论】:

    【解决方案2】:

    问题是你每次迭代都指向同一个位置的指针:

    char* m[ 3]={ "123","456","789"};
    for( char* st = *m; st != 0; st = *( m + 1))
                                   // ^^^^^^^^^  <- this doesn't change, 
                                   //               st points to *(m+1)
    {
        std::cout << st;
    }
    

    另外您不应该使用非常量 char * 指向不可修改的字符串文字:

    const char* m[ 3]={ "123","456","789"};
    const unsigned int n = sizeof( m) / sizeof( m[ 0]);
    
    for( const char** st = m; st != (m + n) ; st ++ )
    {
        cout << *st;
    }
    

    即使基于范围的迭代也可以工作:

    const char* m[ 3] = { "123", "456", "789" };
    for ( const char* st : m )
    {
        std::cout << st << std::endl;
    } 
    

    如果由于某种原因您必须坚持简单的迭代,这也可以:

    const char* m[ 3]={ "123","456","789"};
    const char* st;
    int r = 0;
    for( st = *m; r < 3; st = *( m+r))
    {
        std::cout << st << std::endl;
        r++;
    }
    

    请考虑使用标准容器,即std::vectorstd::array。它将对您有很大帮助,主要是在动态内存管理方面。

    std::vector< std::string> v = { "123", "456", "789"};
    for ( auto& s : v) 
        std::cout << s;
    

    【讨论】:

    • 为什么要使用char** 而不是只使用char*
    • 因为我想使用指针增量迭代数组,st++作为指针将被正确递增以指向下一个元素,即const char *,所以指针本身必须是const char **
    • 只使用char* st = m,增加它并输出cout &lt;&lt; st;有什么问题?条件为st!=m[n]st!=*(m+n)
    • 这不行,m衰减为char**,注意声明:char* m[3]
    • 对不起,我的意思是char* st = m[0]。它应该可以工作,不是吗
    【解决方案3】:

    立即停止对字符串使用char*,并开始使用std::string。 C 风格的数组也是如此:开始使用std::arraystd::vector。这将为您节省数年的生命和不必要的痛苦。

    看看这段代码有多漂亮:

    std::array<std::string, 3> m = {"123", "456", "789"};
    for (auto& s : m) 
        std::cout << s;
    

    here 是活生生的例子。

    【讨论】:

    • +1 如果强制要求 OP 使用 char const* m[],他们至少应该利用这个答案的第二部分,即基于语言的范围枚举器, 使用固定数组(即将m 更改为具有适当const-ness 的OP 数组,并且代码仍将编译)。 See it live
    【解决方案4】:

    你写的循环无效

    char* m[3]={"123","456","789"};
    for(char* st=*m;st!=0; st=*(m+1))
    {
        cout <<st;
    } 
    

    表达式*m 的类型为char *,而数组m 不包含NULL 指针。所以条件st!=0; 是错的。并且指针总是指向同一个元素,因为表达式 st=*(m+1) 总是给出数组的第二个元素

    还要考虑到数组的正确定义会是

    const char* m[3] = { "123", "456", "789" };
    

    因为它是一个指向字符串字面量的指针数组,而字符串字面量不能改变。

    您可以简单地使用基于范围的 for 语句

    const char* m[3] = { "123", "456", "789" };
    for ( const char* st : m )
    {
        cout <<st << std::endl;
    } 
    

    或者你可以在循环中使用迭代器。例如

    const char* m[3] = { "123", "456", "789" };
    for ( auto it = std::begin( m ); it != std::end( m ); ++it )
    {
        cout << *it << std::endl;
    } 
    

    你可以使用标准算法std::copy

    #include <iostream>
    #include <algorithm>
    #include <iterator>
    
    //,,, 
    const char* m[3] = { "123", "456", "789" };
    std::copy( std::begin( m ), std::end( m ),
               std::ostream_iterator<const char *>( std::cout, "\n" ) ); 
    

    【讨论】:

      猜你喜欢
      • 2023-02-13
      • 1970-01-01
      • 2018-03-30
      • 2018-08-02
      • 2012-08-22
      • 1970-01-01
      • 2013-08-31
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多