使用 std::copy 复制数组时出现分段错误

Posted

技术标签:

【中文标题】使用 std::copy 复制数组时出现分段错误【英文标题】:getting segmentation fault when copying arrays using std::copy 【发布时间】:2019-05-08 16:36:53 【问题描述】:

我正在尝试执行帕斯卡三角形,我需要将一个数组复制到另一个数组,我目前正在使用复制功能,但遇到了著名的分段错误。

这是我的代码:

    #include <iostream>
    #include <algorithm> 
    #include <cstring>

    using namespace std;

    void print(const int *tab, const int &nbr)
        for(int i = 0; i<nbr;i++)
          cout << tab[i];
         

        cout << endl;
     


     int main()
     
       int *tab;
       int *tab1;
       int index = 0;
       cout << "enter a number less than or equal to 20!" << endl;
       int number = 40;
       while(number > 20)
         cin >> number;
         cout << endl;
       

       int a = 1;

       while(index < number)
         tab[0] = 1;
         for(int i=1;i<=index;i++)
            tab[i] = i;
         
         print(tab,index);
         std::copy(tab,tab+index,tab1);
         index++;
       

       return 0;
     

我在使用 memcpy 函数时遇到了同样的错误,任何人都可以

【问题讨论】:

我建议您使用 std::vector&lt;int&gt; 而不是原始指针。 @yes 目前尚不清楚您在 while 循环中要实现的目标。 想象你有一本电话簿,里面全是房子的地址……除了那些地段上没有任何房子,你告诉某人去那个地址的其中一间卧室睡觉。睡不着觉 您可以使用vector&lt;int&gt; tab = 1, 2, 3, 4, 5;std::array&lt;int, 5&gt; tab = 1, 2, 3 , 4, 5;int* tab = new int[5]1, 2, 3, 4, 5;。我会建议向量,以便您可以执行 std::copy_n(tab.being(), index, tab1.begin());std:copy(std::begin(tab), std::end(tab) + index, std::being(tab1));std::copy_n(tab.being(), index, tab1.begin()); 。毕竟,你在做C++,而不是C 【参考方案1】:

(在您的版本之前)

使用 std::copy 复制数组时出现分段错误

问题出现在std::copy之前

拥有

 int *tab;
 int *tab1;
 ...
 tab[i] = tab1[i];

tabtab1 未初始化,它们不指向用作数组的内存块,因此行为未定义(在您的情况下是分段错误) 每次被取消引用时

关于 number 的代码,您可能想要类似

int tab[20];
int tab1[20]

警告

 for(int i=1;i<=index;i++)

您似乎认为数组的第一个索引是 1,而它是 0


您的代码中的一项建议(在您的版本之后)删除未定义的行为,更多其他更改,我评论了修改。

#include <iostream>
#include <algorithm> 
#include <cstring>

using namespace std;

void print(const int *tab, const int &nbr)
  for(int i = 0; i<nbr;i++)
    cout << tab[i] << ' '; // add a space to separate numbers 
  

  cout << endl;


int main()

  int number;

  do  // your case it typically a "do while"
    // print moved inside to clearly indicate the expected input
    // even after a number invalid
    // and also request a  number > 0 else no sence after
    cout << "enter a number between 1 and 20!" << endl;
    if (!(cin >> number))  // detect the error else if a non number you loop forever
      cerr << "invalid input" << endl;
      cin.clear(); // clear the error

      // bypass invalid input
      string s;

      if (! (cin >> s)) 
        // EOF !
        return -1;
      
      number = 0; // to reloop
    
   while ((number > 20) || (number <= 0));

  int * tab = new int[number]; // added missing initialization
  int * tab1 = new int[number]; // added missing initialization

  for (int index = 0; index < number; ++index) 
    tab[0] = 1;
    for(int i=1; i<=index; i++) 
      tab[i] = i;
    
    print(tab,index);
    std::copy(tab, tab+index, tab1);
  

  // free resources
  delete [] tab;
  delete [] tab1;

  return 0;

编译和执行:

pi@raspberrypi:/tmp $ g++ -pedantic -Wextra -Wall cp.cc
pi@raspberrypi:/tmp $ ./a.out
enter a number between 1 and 20!
aze
invalid input
enter a number between 1 and 20!
-1
enter a number between 1 and 20!
21
enter a number between 1 and 20!
20

1 
1 1 
1 1 2 
1 1 2 3 
1 1 2 3 4 
1 1 2 3 4 5 
1 1 2 3 4 5 6 
1 1 2 3 4 5 6 7 
1 1 2 3 4 5 6 7 8 
1 1 2 3 4 5 6 7 8 9 
1 1 2 3 4 5 6 7 8 9 10 
1 1 2 3 4 5 6 7 8 9 10 11 
1 1 2 3 4 5 6 7 8 9 10 11 12 
1 1 2 3 4 5 6 7 8 9 10 11 12 13 
1 1 2 3 4 5 6 7 8 9 10 11 12 13 14 
1 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 
1 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 
1 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 
1 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 
pi@raspberrypi:/tmp $ 

然而在

for (int index = 0; index < number; ++index) 
  tab[0] = 1;
  for(int i=1; i<=index; i++) 
    tab[i] = i;
  
  print(tab,index);
  std::copy(tab, tab+index, tab1);

tab被初始化了很多次都白费,每个条目只初始化一次就够了

std::copy(tab, tab+index, tab1); 没用,因为 tab1 从未使用过。

可以删除所有与 tab1 相关的内容,只保留:

tab[0] = 1;
for (int index = 1; index < number; ++index) 
  tab[index] = index;
  print(tab,index);

valgrind 下执行以检查内存访问和泄漏(tab1 已删除):

pi@raspberrypi:/tmp $ valgrind ./a.out
==16633== Memcheck, a memory error detector
==16633== Copyright (C) 2002-2017, and GNU GPL'd, by Julian Seward et al.
==16633== Using Valgrind-3.13.0 and LibVEX; rerun with -h for copyright info
==16633== Command: ./a.out
==16633== 
enter a number between 1 and 20!
10
1 
1 1 
1 1 2 
1 1 2 3 
1 1 2 3 4 
1 1 2 3 4 5 
1 1 2 3 4 5 6 
1 1 2 3 4 5 6 7 
1 1 2 3 4 5 6 7 8 
==16633== 
==16633== HEAP SUMMARY:
==16633==     in use at exit: 0 bytes in 0 blocks
==16633==   total heap usage: 4 allocs, 4 frees, 22,312 bytes allocated
==16633== 
==16633== All heap blocks were freed -- no leaks are possible
==16633== 
==16633== For counts of detected and suppressed errors, rerun with: -v
==16633== ERROR SUMMARY: 0 errors from 0 contexts (suppressed: 6 from 3)
pi@raspberrypi:/tmp $ 

还请注意您错过了打印 print

中的最后一个元素
for(int i = 0; i<nbr;i++)

可以

for(int i = 0; i<=nbr;i++)

【讨论】:

对不起,我编辑了我的帖子,标签已初始化,我想将其内容复制到 tab1。 @πάνταῥεῖ 但问题不是制表符,因为我可以通过调用打印函数打印其内容,问题是 tab1,tab1 被声明为指针,所以我可以这样做std::copy(tab,tab+index,tab1); @lyes 好吧,未定义的行为未定义,这意味着任何事情都可能发生。 @lyes 你错过了初始化它们,你明白这个问题吗?我想您想像我在回答中所说的那样拥有数组 @lyes 我用你的代码的更正版本编辑了我的答案(因为我能理解你想要什么)【参考方案2】:

我看到的问题:

    在使用 tabtab1 之前,您还没有为它们分配内存,就好像它们指向有效内存一样。这会导致未定义的行为。

    您没有任何代码可以用数据填充tab。没有这个,从tab 复制到tab1 是没有意义的。 更新后的代码初始化tab

【讨论】:

tab[0] 已初始化,只是忘记了这一行,这就是为什么我从 1 开始索引,数组被声明为指针,你的意思是我不能直接开始填充它? @lyes,是的,你可以。我错过了。

以上是关于使用 std::copy 复制数组时出现分段错误的主要内容,如果未能解决你的问题,请参考以下文章

在 C 中创建大型数组时出现分段错误

初始化数组时出现段错误

将指向数组的指针传递给函数时出现分段错误(C++)

对函数进行字节编码时出现分段错误? [复制]

我运行程序时出现“分段错误(核心转储)”

尝试在 C 中使用 realloc 扩展数组时出现分段错误错误 [关闭]