一个程序,用于对 2 个数组求和并在第三个数组中显示输出。它显示运行时错误。为什么?



我编辑了代码。但现在它显示运行时错误。谁能说出为什么?这是一个对 2 个数组求和并在第三个数组中显示输出的程序。 我还想知道是否可以优化此代码?

void sumOfTwoArrays(int arr[], int size1, int brr[], int size2, int crr[])
{
int k;
if(size1>size2){
k = size1;
}
else
k = size2;
int c = k;
int r = 0;
int i = size1-1;
int j = size2-1;
for(;i>=0&&j>=0;i--,j--){
int n = arr[i] + brr[j] + r;
if(n<=9){
crr[c] = n;
}
else
{
int r = n/10;
n = n%10;
crr[c] = n;
}
c--;
}
while(arr[i]>=0){
crr[c] = arr[i] + r;
r = 0;
c--;
}
while(brr[j]>=0){
crr[c] = brr[j] + r;
r = 0;
c--;
}
if(r!=0){
crr[c] = r;
}
}

你在块范围内声明变量,即在{ ... }内部,这些变量只在这个块中可见:

if(size1>size2){ 
int crr[size1+1];
int c = size1;
}
else{
int crr[size2+1];
int c = size2;
}
...
crr[c] = ...  // neither crr nor c are valid here any more

顺便说一句:C++不支持像int crr[size1+1]这样的可变长度数组(当size不是编译时常量时)。

为了克服这个问题,写...

int *crr;
int c;
if(size1>size2){ 
crr = new int[size1+1];
c = size1;
}
else{
crr = new int[size2+1];
c = size2;
}
...
delete[] crr;

关于范围问题:参见斯蒂芬的回答。

我还想知道是否可以优化此代码

通过使用std::vector.好的,如果您也可以在外面使用向量,则以下内容只是一个不错的选择——将原始数组复制到向量中也不会有效率......但如果可以的话,那么您可能会喜欢这个变体:

template <typename T> // optional: you're more flexible if you make a template of...
void sumOfTwoArrays(std::vector<T> const& va, std::vector<T> const& vb, std::vector<T>& vr)
{
vr.resize(std::max(va.size(), vb.size() + 1));
int carry = 0; // renamed r to something more meaningful
// these pairs will help to avoid code duplication later
std::pair pa(va, va.rbegin());
std::pair pb(vb, vb.rbegin());
auto ir = vr.rbegin();
while(pa.second != pa.first.rend() && pb.second != pb.first.rend())
{
// just skip the if/else:
// assume you have arbitrary number, the else case will be entered anyway
// in 50 % of the cases - in the other 50 %, the else branch calculates
// the correct result, too; and on most modern machines, the branch is
// rather expensive, so you result in easier code and have quite a good
// chance to even perform better...
carry += *pa.second + *pb.second;
*ir = carry % 10;
carry /= 10;
++ir, ++pa.second, ++pb.second;
}
// avoiding of two identical while loops: iterate over the two pairs...
for(auto p : { pa, pb })
{
// just loop over, if we are already at the end, won't enter...
while(p.second != p.first.rend())
{
// STILL need to continue calculating the carry!
// imagine we have set it and ciphers following are all 9!
carry += *p.second;
*ir = carry % 10;
carry /= 10;
++ir, ++p.second;
}
}
// assign either 0 or 1...
*ir = carry;
}

变体:您可以擦除最后的第一个元素,而不是分配 0:

if(carry == 0)
{
vr.erase(vr.begin());
}
else
{
*ir = carry;
}

请注意,这会将所有元素移动到前面一个位置。另一方面,如果您重复添加已经包含前导零的向量,如果您不再删除它,您可能会一次又一次地在不需要的情况下预置另一个向量。

如果您反转向量中数字的顺序,在位置 0 处具有最不重要的数字,您将不会遇到任何问题(您将rbegin()rend()begin()end()交换,但会使用前者来打印数据以显示......最后的擦除将是一个O(1)操作,然后:

if(carry == 0)
{
vr.erase(std::previous(vr.end())
}
// ...

以上所有这些只有在保持向量规范化的情况下才能按预期工作(即 0 到 9 之间的所有数字(包括 0 和 9)。您可以考虑将向量打包到一个单独的类中,以便数据对用户隐藏,并且只能以受控方式进行修改(假设您有一个精细的向量,但用户确实v[7] = -1012......

运行时错误表明这是一个内存问题,即您正在写入一些未分配给代码使用的内存。因此,正如其他贡献者所提到的,您应该为数组分配适当的内存。

以下是代码的修改版本,工作正常。您可以在此处看到它的工作原理:

void sumOfTwoArrays(int arr1[], int size1, int arr2[], int size2, int sumArr[])
{
int maxLen;
int* tArry;
int l;
if(size1>size2) { maxLen = size1; tArry = arr1; l = size1 - size2; }
else { maxLen = size2; tArry = arr2; l = size2 - size1; }
int carry = 0;
while(size1 && size2){
carry += arr1[--size1] + arr2[--size2];
sumArr[maxLen--] = carry%10;
carry /= 10;
}
while(l){
carry += tArry[--l];
sumArr[maxLen--] = carry%10;
carry /= 10;
}
sumArr[maxLen] = carry;
}

调用代码如下所示:

... 
int a[] = {9,9,9,9,9};
int b[] = {1};
int l1 = sizeof(a) / sizeof(int), l2 = sizeof(b)/sizeof(int);
int l3 = ((l1 > l2) ? l1 : l2) + 1;
int *c = new int[l3];
sumOfTwoArrays(a, l1, b, l2, c);
...
delete [] c;
... 

最新更新