所以我正在编写一个账单处理系统。数据当前位于我编写的Stack
结构中。
我有这个部分编写的函数来写出一份报告:
void GenerateReport(Bill* bill)
{
PrintBillHeading(bill);
//CallEntry* collatedEntries = CollapseCallStack(bill->callEntries);
//TODO
}
只要我把第二行注释掉,就可以正常工作。如果我取消注释它,我会在下面指示的 PrintBillHeading()
函数中出现 SIGSEGV 故障。
void PrintBillHeading(Bill* bill)
{
printf("Big Brother Telecomn");
printf("Bill Date: %snn",DateTimeToISOString(bill->date));
printf("Contract Holder: %s %sn", bill->title, bill->name);
printf("Address:n");
char* addressSeg;
char* addressCpy;
strcpy(addressCpy,bill->address); //This line throws the SIGSEGV
while ((addressSeg = strtok_r(addressCpy,";",&addressCpy)))
{
printf("%sn ",addressSeg);
}
}
为了完整起见,这是我的CollapseCallStack()
函数,这是不完整的,完全未经测试的,可能不起作用。
CallEntry* CollapseCallStack(Stack* calls)
{
int size = calls->topIndex;
CallEntry* collatedSet = malloc(sizeof(CallEntry) * size);
CallEntry* poppedCall;
int curIndex = 0;
while (PopStack(calls,poppedCall))
{
bool found = false;
for (int i = 0; i < size; i++)
{
CallEntry* arrItem = collatedSet + i * sizeof(CallEntry);
if (StringEquals(arrItem->phoneNumber,poppedCall->phoneNumber))
{
found = true;
arrItem->minutes += poppedCall->minutes;
}
}
if (!found)
{
memcpy(collatedSet,poppedCall,sizeof(CallEntry)); //
}
}
}
和CallEntry
结构:
typedef struct{
char* phoneNumber;
int minutes;
DateTime* callDateTime;
} CallEntry;
我的问题是:尚未调用的函数如何导致 SIGSEGV 错误在程序的早期表达?
一旦我解决了这个问题,我就可以自己调试CollapseCallStack()
函数,尽管如果有人看到任何明显的问题,我将不胜感激。
> 在函数PrintBillHeading()
中,语句 strcpy(addressCpy,bill->address)
使用未初始化变量的值addressCpy
。这是未定义的行为。未定义的行为意味着程序可能会在任何随机位置崩溃。如果程序包含未定义的行为,则整个程序无效。
除了 AlexP 的正确答案之外,我还想指出另一个(潜伏的)未定义的行为:
void GenerateReport(Bill* bill)
{
PrintBillHeading(bill);
CallEntry* collatedEntries = CollapseCallStack(bill->callEntries);
//TODO
}
现在,当前实现中的CollapseCallStack
不会返回任何内容。它仍然会被调用,实际上,在初始化它时,某些东西会分配给你的collatedEntries
指针。
问题是,当调用CollapseCallStack
时,返回值的内存被分配,但它永远不会被分配一个有意义的值,因为缺少 return 语句。因此,本质上,您的collatedEntries
指针将使用随机垃圾值进行初始化,如果您尝试取消引用它,则会导致 UB。