【问题标题】:C segmentation fault with array数组的 C 分段错误
【发布时间】:2016-06-26 18:05:43
【问题描述】:

我正在逐块编写代码,并尝试在此过程中使用指针算法。我的代码调用一个函数,然后假设向用户询问 8 个数字。然后使用指针将数字存储到数组中。我的问题是我遇到了分段错误。我相信这个问题与我的指针和地址有关。我认为导致此问题的代码块是scanf("%lf", *(coeff+1));。这是引发故障的区域吗?如果是,有什么方法可以解决这个问题?

#include <stdio.h>

void get_poly(double *coeff){

  int p;

  printf("Enter the eight coefficients: ");
    for(p = 0; p < 7; p++){
      scanf("%lf", *(coeff+1));
    }
}

int main(void){

  int i;
  double coeff[7];

  get_poly(coeff);

  printf("output");
    for(i = 0; i < 7; i++){
      printf("%lf",coeff[i]);
   }  
  return 0;
}

【问题讨论】:

  • 代码中有多个问题。首先,您应该将地址传递给 scanf。在这里,您正在传递一个值。第二个缺陷在逻辑上。你总是传递第一个槽的地址(在你更正之前)。
  • scanf("%lf", *(coeff+1)); --> scanf("%lf", coeff+p);
  • 开启编译器警告,通常使用-Wall。他们准确地指出了问题所在。传入一个已经分配的指向get_poly 的指针是不必要的复杂化。调用者需要进行分配并且需要知道get_poly 将读取多少个数字。你最好让get_poly 自己分配内存并返回double *。然后您可以使用参数来说明要读取多少个数字。

标签: c arrays function pointers


【解决方案1】:
  scanf("%lf", *(coeff+1));

在这里,您将错误类型的参数发送到scanf() 函数,因为*(coeff+1) 的类型为double,而scanf() 需要一个指向double 的指针,即double* 类型参数。

解决方案:删除*(取消引用)运算符


for(p = 0; p < 7; p++)
{
  scanf("%lf", coeff+1);
}

没有给出错误,但它只填充第 2ndcoef[1] 元素在每次迭代中.. 相反,您可以使用 p 填充整个数组

for(p = 0; p < 7; p++)
{
  scanf("%lf", coeff+p);
}

【讨论】:

    【解决方案2】:

    打开编译器警告,问题就很清楚了。

    $ make
    cc -Wall -g    test.c   -o test
    test.c:9:20: warning: format specifies type 'double *' but the argument has type 'double' [-Wformat]
          scanf("%lf", *(coeff+1));
                 ~~~   ^~~~~~~~~~
    1 warning generated.
    

    scanf 想要一个双精度指针,但它被输入了一个双精度值。

    您要做的是通过循环增加coeff 以模拟coeff[p]*(coeff+1) 实际上所做的是获取 coeff 指向的值并将其加 1。这类似于coeff[0] + 1scanf 将此数字(这将是乱码)视为内存地址,程序崩溃。

    你想要的是增加指针本身。但不是 1,coeff + 1 类似于 coeff[1]。而是使用p:coeff + p


    您也有两次相同的差一错误。您的 for 循环仅迭代 7 次。

    for(i = 0; i < 7; i++) {
                   ^
    

    这将从 0 变为 6。一个简单的经验法则是,如果您想迭代 N 次,则输入 i &lt; N。这是有效的,因为数组是 0 索引的。


    get_poly 的设计方式而言,这里几乎没有理由要求用户传入一个已经分配的指针。这需要用户做额外的工作,并知道get_poly 将读取多少元素。如果get_poly 想阅读更多,所有调用它的代码都会中断。

    改为让get_poly 进行分配。然后你也可以使用参数来询问它应该读取多少个数字。这使得函数更安全、更灵活。

    最后,我一直将i 用于for 循环迭代器。这是一个标准约定,使用p(用于多项式?)掩盖了它只是一个循环迭代器(甚至不计算多项式)。

    #include <stdio.h>
    #include <stdlib.h>
    
    double *get_poly(int num_coeffs){
      int i;
      double *coeffs = calloc(num_coeffs, sizeof(double*));
    
      printf("Enter the %d coefficients: ", num_coeffs);
      for(i = 0; i < num_coeffs; i++){
          scanf("%lf", coeffs + i);
      }
    
      return coeffs;
    }
    
    int main(void){
      int i;
    
      double *coeffs = get_poly(8);
    
      printf("output: ");
    
      for(i = 0; i < 8; i++){
          printf("%lf ",coeffs[i]);
      }
    
      printf("\n");
    
      return 0;
    }
    

    您应该避免使用scanf,而是使用fgets + sscanf 代替all the reasons outlined here。我把它留作练习。

    【讨论】:

    • 我总是更喜欢使用size_t而不是int作为大小。
    【解决方案3】:

    此解决方案的答案如下,由@BLUEPIXY提供

    scanf("%lf", *(coeff+1)); --> scanf("%lf", coeff+p);
    

    【讨论】:

    • 您好,欢迎来到 Stack Overflow!虽然这是正确的代码,但要成为一个好的答案,它需要一个解释。没有解释,他们就不会明白哪里出了问题以及将来如何避免它。是的,即使您正在回答自己的问题。 :)
    猜你喜欢
    • 1970-01-01
    • 2021-06-27
    • 2017-04-11
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-12-05
    相关资源
    最近更新 更多