完成关闭功能时C崩溃

时间:2014-11-27 00:41:47

标签: c arrays struct crash parameter-passing

我目前有一个基本的C程序,它可以为结构中的数组生成并保存值。只要调用基本功能,程序就会崩溃。有谁知道这有什么问题?

#define SAMPLES 10   

struct values {
    double values[SAMPLES],mean;  } values;

int main()
{
    struct values array[0];
    setvals(array);
    return 0;
}

void setvals(struct values array[0]){
     int i;
     for( i = 0 ; i < SAMPLES ; i++ ) {
          array[0].values[i] = 2;
          printf("struct val = %f\n",array[0].values[i]);
      }
      printf("exitingfunc");
}

我可以看到结构中的值被设置为2但是只要&#34; exitingfunc&#34;打印整个程序崩溃 - 编译时没有错误或警告。任何想法为什么会这样?

任何和所有帮助appriciated,

谢谢,J

2 个答案:

答案 0 :(得分:2)

大小为0的非堆数组不是合法的标准C.

(您是否正在查看编译器错误/警告输出?某些编译器会允许它,可能会也可能不会抱怨。)

堆上的分配可以为零,并返回一个可以安全释放的指针值。它可能是NULL或有效的内存地址(您不允许访问它)。

虽然在这里你实际上是在尝试使用数组中不存在的第一个(即索引为0)元素。因此声明它有一个元素。

struct values array[1];

当然,您声明一个单元素数组很奇怪。也许你打算稍后使用更大的数字。但是,如果您只想要更改类型值的变量,那么您应该学习如何将指针传递给(即地址)变量以在函数中更改它们:

struct values a;
...
setvals(&a);
...
void setvals(struct values *a){ /* or struct values a[] or a[1] */
    ...
    (*a).values[i] = 2; /* or pa->values[i] */

另请注意,使用数组表示法声明参数时,它仍然只定义指针。

答案 1 :(得分:1)

问题在于以下定义:

struct values array[0];

它将分配一个零元素的数组 - 即根本没有内存。通过在setvals内写入,您将覆盖包含返回地址为main的堆结构。因此,当尝试跳转到地址0x00000002时,会抛出分段错误。将定义更改为

struct values array[1];

并且该程序将起作用(尽管您可能希望将参数列表更改为setvals)。

另请注意

  • 您定义了一个名为values的全局结构,您实际上没有使用它,
  • 而不是将一个元素数组传递给setvals,你可以只传递一个指针,
  • 您最好使用i
  • 的无符号整数
  • 2实际上是一个整数字面值,而不是双字面值(可以是2.),而
  • 打印的字符串"exitingfunc"不会被换行符终止。

考虑到所有事情,您的程序可能如下所示:

#include <stdio.h>

#define SAMPLES 10

struct values {
    double values[SAMPLES], mean;
};

void setvals(struct values *array)
{
    unsigned int i;
    for (i = 0; i < SAMPLES; i++) {
        array->values[i] = 2.;
        printf("struct val = %f\n", array->values[i]);
    }
    printf("exitingfunc\n");
}

int main()
{
    struct values array;
    setvals(&array);
    return 0;
}

有一种用于检查此类错误的有用工具:内存错误检测器memcheck,工具套件的一部分(由命令调用)valgrind。以下是它为您的程序输出的内容:

==6180== Memcheck, a memory error detector
==6180== Copyright (C) 2002-2013, and GNU GPL'd, by Julian Seward et al.
==6180== Using Valgrind-3.10.0 and LibVEX; rerun with -h for copyright info
==6180== Command: ./a.out
==6180==
struct val = 2.000000
struct val = 2.000000
struct val = 2.000000
struct val = 2.000000
struct val = 2.000000
struct val = 2.000000
struct val = 2.000000
struct val = 2.000000
struct val = 2.000000
struct val = 2.000000
==6180== Jump to the invalid address stated on the next line
==6180==    at 0x4000000000000000: ???
==6180==    by 0x3FFFFFFFFFFFFFFF: ???
==6180==    by 0x3FFFFFFFFFFFFFFF: ???
==6180==    by 0x3FFFFFFFFFFFFFFF: ???
==6180==    by 0x3FFFFFFFFFFFFFFF: ???
==6180==    by 0x3FFFFFFFFFFFFFFF: ???
==6180==    by 0x3FFFFFFFFFFFFFFF: ???
==6180==    by 0x3FFFFFFFFFFFFFFF: ???
==6180==    by 0x3FFFFFFFFFFFFFFF: ???
==6180==  Address 0x4000000000000000 is not stack'd, malloc'd or (recently) free'd
==6180==
==6180==
==6180== Process terminating with default action of signal 11 (SIGSEGV)
==6180==  Bad permissions for mapped region at address 0x4000000000000000
==6180==    at 0x4000000000000000: ???
==6180==    by 0x3FFFFFFFFFFFFFFF: ???
==6180==    by 0x3FFFFFFFFFFFFFFF: ???
==6180==    by 0x3FFFFFFFFFFFFFFF: ???
==6180==    by 0x3FFFFFFFFFFFFFFF: ???
==6180==    by 0x3FFFFFFFFFFFFFFF: ???
==6180==    by 0x3FFFFFFFFFFFFFFF: ???
==6180==    by 0x3FFFFFFFFFFFFFFF: ???
==6180==    by 0x3FFFFFFFFFFFFFFF: ???
exitingfunc==6180==
==6180== HEAP SUMMARY:
==6180==     in use at exit: 0 bytes in 0 blocks
==6180==   total heap usage: 0 allocs, 0 frees, 0 bytes allocated
==6180==
==6180== All heap blocks were freed -- no leaks are possible
==6180==
==6180== For counts of detected and suppressed errors, rerun with: -v
==6180== ERROR SUMMARY: 1 errors from 1 contexts (suppressed: 0 from 0)
Segmentation fault

这里的关键信息是

Jump to the invalid address stated on the next line

它告诉你,你要么玩弄函数指针而且结果很糟糕(你没有做过),或者堆栈已经损坏了。反过来,这会指向伪造的本地数组定义。