【问题标题】:Help: Insert elements into array in C!帮助:在 C 中将元素插入数组!
【发布时间】:2023-03-26 20:40:01
【问题描述】:

这是我将数组 B 中的唯一元素合并到数组 A 中的代码。

例如:

输入:A={1, 3, 5, 7, 9}B={2, 4, 6, 9}

输出:A={1, 2, 3, 4, 5, 6, 7, 9}

但我在第 46 行遇到分段错误。我假设这是数组绑定问题,但无法弄清楚。有任何想法吗?


#include <stdio.h>
#define MAXSIZE 100
typedef int ElemType;
typedef struct{
    ElemType data[MAXSIZE];
int length;
}SqList;

void CreateList(SqList *L, int n){
L->length=n;
printf("\ninput %d data: ", n);
int i;
for(i=0;i<n;i++)
    scanf("%d", &L->data[i]);
}   

void PrintList(SqList *L){
int i;
int n;
n=L->length;
printf("\noutput %d data: ", n);
for(i=0;i<n;i++)
    printf("%d", L->data[i]);
}


ElemType GetElem(SqList *L,int i){
return L->data[i];
}

int LocateElem(SqList *L, ElemType e){
int i;
for(i=1;i<=L->length;i++){
    if(L->data[i]==e){
       return i;
       break;
    }
    else return 0;
}
}

void ListInsert(SqList *L, ElemType e){
int n = L->length;
n++;
L->length=n;     
L->data[n]=e;                        // Segmentation Fault Here !
}


void merge(SqList *La, SqList *Lb){
int i;
ElemType e;
for(i=0;i<Lb->length;i++){
    e=GetElem(&Lb,i);   
    if(!LocateElem(&La,e))
        ListInsert(&La,e);
}
}

int main(){
SqList La,Lb;
int n1,n2;
printf("\nInput number for La: ");
scanf("%d",&n1);
CreateList(&La,n1);
printf("\nInput number for Lb: ");
scanf("%d",&n2);
CreateList(&Lb,n2);
printf("Here is La:\n");
PrintList(&La);
printf("Here is Lb:\n");
PrintList(&Lb);
merge(&La,&Lb);
printf("Here is merged list:\n");
PrintList(&La);

return 0;
}

【问题讨论】:

  • 编译你忽略警告

标签: c arrays segmentation-fault


【解决方案1】:

您在merge 代码中使用了过多的&amp;

void merge(SqList *La, SqList *Lb){
  int i;
  ElemType e;
  for(i=0;i<Lb->length;i++){
    e=GetElem(Lb,i);   
    if(!LocateElem(La,e))
      ListInsert(La,e);
  }
}

那么它没有段错误,但我没有检查“逻辑”是否正确(我想是的)

添加

另外,ListInsert 需要修复:

void ListInsert(SqList *L, ElemType e){
  int n = L->length;
  L->data[n]=e;
  L->length++;
}

您的版本跳过一个数组元素,因为您使用“增量大小”来索引新元素,而新插入的值必须放在索引L-&gt;length,然后您需要增加数组的长度(最后大小为 N 的数组的元素为 N-1,因此将大小递增到 N+1,最后一个元素的索引为 N)。

当然你不检查数组边界,所以如果你插入超过 MAXSIZE 个元素,你会遇到麻烦。

添加 2 个

您的 LocateElem 也需要修复:

int LocateElem(SqList *L, ElemType e){
  int i;
  for(i=1;i<=L->length;i++){
    if(L->data[i]==e){
      return i;
    }
  }
  return 0;
}

(我一直保留您使用 0 作为未找到的特殊值的想法,尽管阅读了有关它的评论和 MAXSIZE 演讲;此外,您的更多代码需要修复才能始终如一地使用)。这里的修复是关于当你发现第一个元素不等于 e 时返回的事实,而(我想)如果你没有找到元素,你想返回 0,或者如果你找到它,则返回任何非 0。此固定代码探索整个数组(从 1 开始,如果您为特殊含义保留 0 索引)

【讨论】:

  • 感谢您的回复。我对C很陌生。你是对的。我确实使用了很多 & 并收到了编译器的警告。但是 GetElem、LocateElem 和 ListInsert 的函数原型都以指针类型作为第一个参数。我不应该在函数调用的参数中使用 & 吗?
  • 你已经有指针了!在int func(something *S) 中,参数 S is 是一个指针,所以当你将它用于另一个函数时,比如doIt(S),你已经传递了一个指针,如果 doIt 的 proto 是 @987654329 就可以了@ 或类似的。如果你使用 &,你会得到指向“某物”的指针的存储地址,这不是你想要的。
  • @joansky 一个建议:由于您使用带符号的 int 进行索引,所以让 -1 为“未找到”值,并将大小为 N 的数组索引在 [0, N-1] 范围内,自然对于 C 数组。您的选择,IMO,更容易出错,例如在 [1,N] 的 LocateElem 循环中,如果 N=MAXSIZE,则超出 1,因此如果添加元素数量检查,则需要检查是否小于 MAXSIZE-1,或者将数组声明为 data[MAXSIZE+1].. . 正如你所做的那样,你的数据最多可以是 99 (MAXSIZE-1),因为一个“有效”索引 (0) 被“保留”用于特殊用途......有点混乱......
  • 非常感谢您的解释:)
【解决方案2】:

您必须检查 n 不超过 MAXSIZE。分段错误很可能是由缓冲区溢出引起的。

【讨论】:

    【解决方案3】:

    如果长度为 n,则只应使用从 0 到 n-1 的元素。当然你也可以写超过 MAXLIST-1。您应该始终添加代码以检查 L->length

    我确实想知道您为什么选择这种相当复杂的方法。我会将 ListInsert 重命名为 ListAppend,因为您只添加到列表的末尾。

    【讨论】:

    • 非常感谢您的回复。我对 C 很陌生。是的,我应该将它重命名为 ListAppedn。你知道如何使这个函数不“相当复杂”吗?谢谢!
    • 好吧,也许“相当复杂”的评论有些过头了。我再次查看了您的代码,它看起来不错。使用这么多函数只是为了进行合并可能有点过头了,但我认为这些函数也可以在其他代码中使用。
    【解决方案4】:

    这里有一些错误可能是您的问题的原因:

    int LocateElem(SqList *L, ElemType e){
    int i;
    for(i=1;i<=L->length;i++){
        if(L->data[i]==e){           // <-- You need to check data[i-1]
           return i;                 //     since you span [1,length] (off by one)
           break;
        }
        else return 0;               // <-- This goes to outside of the loop,
    }                                //     otherwise only the first item is queried
    }
    
    void ListInsert(SqList *L, ElemType e){
    int n = L->length;
    n++;
    L->length=n;     
    L->data[n]=e;                    // <-- You want to modify data[n-1]
    }                                //     since n is already incremented here
    

    【讨论】:

    • 谢谢,我太粗心了,没注意这些花样:(
    【解决方案5】:

    LocateElem 函数在我看来有问题。如果循环中的第一个测试失败,为什么它返回 0?为什么在 return 语句之后要休息?似乎有几行被打乱了...... break 应该去并且 return 0 在 for 块之后移动。

    【讨论】:

    • ISTM 循环看起来不对:我会使用 (i = 0; i length; ++i) 所以没有必要使用 L->data[i-1] 和返回正确的 i。确实,突破永远达不到,所以没用。
    • @Rudy OP 的意图是使用 0 作为特殊值来表示未找到。不愉快的选择,-1 会更好......(而且它有问题)
    • 非常感谢您的意见。我修复了我的代码,它现在可以工作了:)
    • @ShinTakezou:对不起,我错过了。
    猜你喜欢
    • 1970-01-01
    • 2017-11-06
    • 2017-12-13
    • 2019-03-08
    • 2021-11-04
    • 1970-01-01
    • 2021-10-03
    • 2014-12-10
    • 2015-10-22
    相关资源
    最近更新 更多