2017-04-02 169 views
1

我试图写一个程序,从CIN使用指针读取的值,然后输出该值沿着他们的阵列中的位置。我无法弄清楚为什么printNumbers1有效,但printNumbers2不能。下面是程序(接近底部的相关代码):C++指针/ for循环混乱

#include <iostream> 

using namespace std; 

int *readNumbers(int); 
void printNumbers1(int*); 
void printNumbers2(int*); 

int main() 
{ 
    int *numbers = readNumbers(5); 
    printNumbers1(numbers); 
    printNumbers2(numbers); 
    return 0; 
} 

int *readNumbers(int n) 
{ 
    int a[n]; 
    int *numbers; 
    numbers = &a[0]; 
    for (int i=0; i<n; i++) 
    { 
     cin >> *(numbers+i); 
    } 

    return numbers; 
} 

void printNumbers1(int *numbers) 
{ 
    cout << 0 << ' ' << *(numbers) << endl 
     << 1 << ' ' << *(numbers+1) << endl 
     << 2 << ' ' << *(numbers+2) << endl 
     << 3 << ' ' << *(numbers+3) << endl 
     << 4 << ' ' << *(numbers+4) << endl; 
} 

void printNumbers2(int *numbers) 
{ 
    for (int i=0; i<5; i++) 
    { 
     cout << i << ' ' << *(numbers+i) << endl; 
    } 
} 

当我运行程序,它可以作为用于printNumbers1但输出看似随机数和0的printNumbers2的组合。我觉得这两个printNumbers函数应该具有相同的功能,但它们不会。我错过了什么?

+0

'a'是一个局部变量。它将超出范围并在函数结束时变为无效。返回一个指向它的指针是一个坏主意,因为指针将指向坏内存。你很可能不得不使用'new'和'delete'。 – user4581301

回答

2

这是因为两件事情的组合:

  • C++不允许变长数组 - 这是一个受欢迎的扩展,但该声明int a[n]不是标准。
  • 您不能从函数 - 指针numbers内部返回指向局部变量的指针readNumbers指向a,即局部变量。你可以在函数内部使用这个指针,但是在函数之外它会变得无效,因为a超出了范围。

使用外的范围的变量会导致未定义行为This Q&A提供了一个非常好的解释发生了什么,以及它为什么看起来像程序工作正常。

如果你想使用内置的指针,删除int a[n],并改变numbers声明如下:

int *numbers = new int[n]; 

您还需要添加

delete[] numbers; 

之前return 0线,以避免内存泄漏。

我假设你写了这个代码作为学习活动的一部分。但是,一般来说,C++中更好的方法是使用std::vector<int>,它隐藏了代码中的指针操作,并为您处理资源管理。

+0

谢谢!唯一让我困惑的是为什么'printNumbers1'工作,如果'a'超出'readNumbers'之外的函数的作用域。 –

+0

@MemelordSupreme如果一个数组超出范围,它并不意味着它有随机垃圾:它可能有你以前放在那里的东西,所以,不幸的是,不正确的代码可能会显示工作。然而,这并不是真的有效,只是随机垃圾恰好符合你期望看到的情况。 – dasblinkenlight

+0

@dasblinkenlight请添加关于未定义行为的注释;那是什么导致看似正确的行为。 –

1

readNumbers指针返回到具有自动存储持续时间的变量。

上废弃该指针的行为是不确定的。

使用一个std ::向量来代替。依靠返回值优化来消除正在进行的任何多余值副本。

0

在这里已创建的数组a [n]的在函数内部,所以它是一个局部变量,因此,这种阵列可以或可以不被所述功能的ends.Never使用本地变量的地址范围后删除在功能之外。此代码正在工作:

#include <iostream> 

using namespace std; 

int *readNumbers(int); 
void printNumbers1(int*); 
void printNumbers2(int*); 

int main() 
{ 
    int *numbers = readNumbers(5); 
    printNumbers1(numbers); 
    printNumbers2(numbers); 
    return 0; 
} 

int *numbers; 

int *readNumbers(int n) 
{ 

    numbers = new int[n]; 
    for (int i=0; i<n; i++) 
    { 
     cin >> *(numbers+i); 
    } 

    return numbers; 
} 

void printNumbers1(int *numbers) 
{ 
cout << 0 << ' ' << *(numbers) << endl 
    << 1 << ' ' << *(numbers+1) << endl 
    << 2 << ' ' << *(numbers+2) << endl 
    << 3 << ' ' << *(numbers+3) << endl 
    << 4 << ' ' << *(numbers+4) << endl; 
} 

void printNumbers2(int *numbers) 
{ 
for (int i=0; i<5; i++) 
{ 
    cout << i << ' ' << *(numbers+i) << endl; 
} 
} 
+0

强烈建议使用[]而不是指针数学进行索引。 – user4581301