【发布时间】:2013-09-16 12:18:32
【问题描述】:
我是 C 新手,但我目前正在开发一个 C 程序,但我遇到了与结构和内存分配相关的问题。
我的代码中有一个永久的 while 循环,它会在满足某个条件时中断。在这个 while 循环中,它检查数据库并有一个 while 循环来循环 MySQL 行。
当程序第一次加载时,它会创建 3 个结构,其中一个结构还包含一个链表并初始化为 100 的大小。
当我的程序循环遍历 MySQL 行时,它会检查是否添加了 100 条记录,如果是,则执行 realloc 以将大小再增加 100 行。当我遍历所有 MySQL 行时,它会返回到 main while 循环(永无止境的循环)和 NULL 的结构,然后再次将它们初始化为 100 行并重新开始。
我遇到的问题是,一旦它对所有 mysql 行进行了第一次完整循环并返回到主永不结束的循环,并且结构被重新初始化为 100 的大小,在我的程序的第 17 行段错误。当我检查 GDB 中的所有内容时,索引 17 处的结构出现说结构中的某些元素超出了界限。
以下是我遇到问题的结构的定义。
typedef struct CallLogSearchDataStruct
{
char * date;
char * time;
char * bParty;
char * aParty;
float duration;
char * cleardownCause;
struct CallLogSearchOutboundStruct * outboundLegs;
} callLogSearchDataStruct;
下面是程序第一次运行时结构的初始设置方式
callLogSearchData = calloc(INITIAL_CALL_STRUCT_SIZE,sizeof(callLogSearchDataStruct));
callLogSearch = calloc(INITIAL_CALL_STRUCT_SIZE,sizeof(callLogSearchResultStruct));
switches = calloc(INITIAL_CALL_STRUCT_SIZE, sizeof(switchIDStructure));
INITIAL_CALL_STRUCT_SIZE 等于 100。
下面是如何调用 reallocateStructures 函数的代码。这通过在原始大小上再增加 100 来重新分配结构。
if (reallocateStructures(&callLogSearch, &callLogSearchData, &switches, ×StructHasBeenReallocated, currentStructIndexValue, dataRow) == 0)
{
//Structures have been reallocated so reset the index
currentStructIndexValue = 0;
}
以下是重新分配结构的实际代码
int reallocateStructures(callLogSearchResultStruct **callLogSearch, callLogSearchDataStruct ** callLogSearchData,
switchIDStructure ** switches, int *timesStructHasBeenReallocated, int currentStructIndexValue,
int dataRow)
{
int INITIAL_CALL_STRUCT_SIZE = 100;
int currentSize = 0;
int newSize = 0;
int initFromIndex = 0;
callLogSearchResultStruct * callLogSearchTemp;
callLogSearchDataStruct * callLogSearchDataTemp;
switchIDStructure * switchesTemp;
printf("Current Struct Index Value: %i\n", currentStructIndexValue);
if (currentStructIndexValue >= INITIAL_CALL_STRUCT_SIZE) {
printf("REALLOCATING STRUCTURES");
currentSize = currentStructIndexValue * *timesStructHasBeenReallocated;
newSize = currentSize + INITIAL_CALL_STRUCT_SIZE;
*timesStructHasBeenReallocated = *timesStructHasBeenReallocated + 1;
callLogSearchTemp= (callLogSearchResultStruct*)realloc(*callLogSearch, (newSize * sizeof(callLogSearchResultStruct)));
callLogSearchDataTemp = (callLogSearchDataStruct*)realloc(*callLogSearchData, (newSize * sizeof(callLogSearchDataStruct)));
switchesTemp = (switchIDStructure*)realloc(*switches, (newSize * sizeof(switchIDStructure)));
/**callLogSearchData = realloc(*callLogSearchData, newSize * sizeof (callLogSearchDataStruct));
*callLogSearch = realloc(*callLogSearch, newSize * sizeof (callLogSearchResultStruct));
*switches = realloc(*switches, newSize * sizeof (switchIDStructure));
*/
for (initFromIndex = currentSize; initFromIndex < newSize; initFromIndex++) {
callLogSearchDataTemp[initFromIndex].aParty = NULL;
callLogSearchDataTemp[initFromIndex].bParty = NULL;
callLogSearchDataTemp[initFromIndex].cleardownCause = NULL;
callLogSearchDataTemp[initFromIndex].date = NULL;
callLogSearchDataTemp[initFromIndex].duration = 0;
callLogSearchDataTemp[initFromIndex].outboundLegs = NULL;
callLogSearchDataTemp[initFromIndex].time = NULL;
callLogSearchTemp[initFromIndex].date = NULL;
callLogSearchTemp[initFromIndex].dRowIndex = dataRow;
switchesTemp[initFromIndex].switchID = NULL;
if (initFromIndex == newSize - 1)
{
printf("debugging here\n");
}
}
*callLogSearch = callLogSearchTemp;
*callLogSearchData = callLogSearchDataTemp;
*switches = switchesTemp;
return 0;
}
else
{
return 1;
}
}
下面是循环遍历所有 MySQL 行的代码,然后将结构重置并重新初始化为 100 的大小。
//Check if function has looped round already and if so reset all structures
if (dataRow > -1)
{
numberOfTimesEverythingHasReset++;
callLogSearchData = NULL;
callLogSearch = NULL;
switches = NULL;
callLogSearchData = realloc(callLogSearchData, INITIAL_CALL_STRUCT_SIZE*sizeof(callLogSearchDataStruct));
callLogSearch = realloc(callLogSearch, INITIAL_CALL_STRUCT_SIZE*sizeof(callLogSearchResultStruct));
switches = realloc(switches, INITIAL_CALL_STRUCT_SIZE*sizeof(switchIDStructure));
//initialiseNewStructure(&callLogSearch, &callLogSearchData, &switches);
//callLogSearchData = (callLogSearchDataStruct*)realloc(callLogSearchData, INITIAL_CALL_STRUCT_SIZE*sizeof(callLogSearchDataStruct));
//callLogSearch = (callLogSearchResultStruct*)realloc(callLogSearch, INITIAL_CALL_STRUCT_SIZE*sizeof(callLogSearchResultStruct));
//switches = (switchIDStructure*)realloc(switches, INITIAL_CALL_STRUCT_SIZE*sizeof(switchIDStructure));
//Initialise all elements within structures
for (initFromIndex = INITIAL_CALL_STRUCT_SIZE; initFromIndex < INITIAL_CALL_STRUCT_SIZE; initFromIndex++)
{
callLogSearchData[initFromIndex].aParty = NULL;
callLogSearchData[initFromIndex].bParty = NULL;
callLogSearchData[initFromIndex].cleardownCause = NULL;
callLogSearchData[initFromIndex].date = NULL;
callLogSearchData[initFromIndex].duration = 0;
callLogSearchData[initFromIndex].outboundLegs = NULL;
callLogSearchData[initFromIndex].time = NULL;
callLogSearch[initFromIndex].date = NULL;
callLogSearch[initFromIndex].dRowIndex = dataRow;
}
timesStructHasBeenReallocated = 1;
currentSize = 0;
}
currentStructIndexValue = 0;
我不确定为什么当它第一次进入 if 语句以将结构重置回 100 的大小时,在 17 MySQL 行之后内存超出范围,所以我出现了段错误。
感谢您提供的任何帮助。
更新 我已经按照@Rohan 的回答解决了 for 循环的问题,但我现在遇到了一个稍微不同的问题。
当我尝试向结构添加数据时,我现在得到了一个不同的区域,但我不确定这些结构是否与它有关,因为它似乎是 MySQL 数组有一个越界问题现在导致一个 seg过错。
失败的那一行是
callLogSearchData[dataRow].bParty = strdup(rowReport[bPartyColIndex]);
当我在 GDB 中检查 rowReport 时,它内部似乎有垃圾,并且在第 7 个索引处(bPartyColIndex 在索引 9 处)我开始看到 out bounds 错误。
rowReport 在每次循环时为每个 mysql 行分配,如下面的代码所示
sqlLen = asprintf(&sql, "SELECT Tmp.SwitchID, Tmp.CorrelationID, SeizeUTC as Date, "
"SeizeUTC as Time, Direction, ACMToAns/100 as ACMToAns, Duration/100 as Duration, "
"CleardownCause, AParty, Tmp.BParty FROM TMP_Log AS Tmp ORDER BY SeizeUTC, "
"Tmp.SwitchID, Tmp.CorrelationID, Direction, SeizeCSec LIMIT %i, %i",
index, count);
SL_DebugAll(DBG_INFO, sql);
if ((mysql_real_query(HandleDB, sql, sqlLen))) return 1;
resultReport = mysql_store_result(HandleDB);
if (mysql_num_rows(resultReport) == 0 || index > atoi(limit))
{
SL_DebugAll(DBG_INFO, "Data retrieval for call log complete");
break;
}
else
{
numRows = mysql_num_rows(resultReport);
swID = -1;
corrID = -1;
dataRow = -1;
if (numRows > 0)
{
maxTargets = 1;
}
audioRow = mysql_fetch_row(audioResult);
sspSwitchID = atoi(audioRow[switchIDColIndex]);
sspCorrID = atoi(audioRow[correlationIDColIndex]);
inbound_counter = 0;
while (rowReport = mysql_fetch_row(resultReport))
【问题讨论】:
-
对不起,你问什么
-
可能不是您的直接问题,但请注意您没有处理可能的 realloc 失败。
-
不要使用变量来表示您重新分配结构的次数,为什么不使用当前索引和大小的变量。 “当前索引”一直向上,并且是分配的“数组”中最后使用的条目的索引。大小是分配的条目数,从
INITIAL_CALL_STRUCT_SIZE开始,它也一直向上增长。如果你增加“当前索引”并且它等于“当前大小”,那么是时候重新分配并增加“当前大小”了。 -
另外,如果
currentStructIndexValue是数组中最后一个条目的索引,那么将其重置为零将导致您覆盖旧条目。 -
@JoachimPileborg 谢谢我不是计算新尺寸的问题,尽管你的建议可能比我使用的更干净。我正在使用一个名为 dataRow 的单独索引来将元素添加到结构中。
currentStructIndexValue将从 0 变为 100,在 100 处重新分配完成,如果返回成功重新分配,则变量重置为 0 并重新开始