我目前有一个基本的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
答案 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
它告诉你,你要么玩弄函数指针而且结果很糟糕(你没有做过),或者堆栈已经损坏了。反过来,这会指向伪造的本地数组定义。