再次出现realloc问题。似乎我在很多以前的realloc语句中找不到任何类似的问题。我很感激你的兴趣。
我正在尝试阅读格式的文本输入:
g:<expression>;0,1,0,1,0
。
我在源文本文件中有一组这种格式的行和一段代码(后面)在“for”循环中读取这一行。 :
和;
之间的表达式被读入propstr
2D char数组。 ;
之后的所有内容都会确定以逗号DIM
分隔的数字的向量(大小为,
)。此向量读入upstr
(就像一个字符串),然后由函数upvec
转换为整数数组process_update_vector
。在循环的每次迭代中,realloc
用于调整所提及的数组的大小(propstr
,upstr
和upvec
)。到目前为止在循环中读取的行数是NREAC
。这是代码:
/*Before this point, current line in the source is read into `temp'*/
NREAC++;
for(i=0;i<strlen(temp);i++){
if(temp[i]==':') colon=i;//Here we find colon
if(temp[i]==';') semicolon=i;//...and semicolon positions
}
memset(temp1,'\0',STRLEN);
if(NREAC==1)
ptrchar=(char **)malloc(sizeof(char *));
else
ptrchar=realloc(propstr,NREAC*sizeof(char *));
if(ptrchar==NULL){
fprintf(stderr,"Error: could not allocate memory for propstr\n");
if(propstr!=NULL) free(propstr);
return 1345;
}else{propstr=ptrchar;ptrchar=NULL;}
propstr[NREAC-1]=(char *)malloc((semicolon-colon)*sizeof(char));
if(propstr[NREAC-1]==NULL){
fprintf(stderr,"Error: couldn't get memory for propstr[NREAC-1]\n");
return 1344;
}
for(i=colon+1;i<semicolon;i++)/*Copy the propensity part of the line*/
temp1[i-colon-1]=temp[i];
temp1[i-colon-1]='\n';/*Include newline symbol for correct parsing*/
strcpy(propstr[NREAC-1],temp1);
memset(temp1,'\0',STRLEN);
if(NREAC==1)
ptrchar=(char **)malloc(sizeof(char *));
else
ptrchar=realloc(upstr,NREAC*sizeof(char *));
if(ptrchar==NULL){
fprintf(stderr,"Error could not allocate memory for upstr\n");
if(upstr!=NULL) free(upstr);
return 1343;
}else{upstr=ptrchar;ptrchar=NULL;}
upstr[NREAC-1]=(char *)malloc((strlen(temp)-semicolon-1)*sizeof(char));
if(upstr[NREAC-1]==NULL){
fprintf(stderr,"Error: couldn't get memory for upstr[NREAC-1]\n");
return 1342;
}
if(strlen(temp)-semicolon==2){/*No vector is specified*/
fprintf(stderr,"Error: no update vector found:\n");
fprintf(stderr,"`%s'",temp);
return 1;
}
if(NREAC==1)
ptrint=(int **)malloc(sizeof(int *));
else
ptrint=(int **)realloc(upvec,NREAC*(sizeof(int *)));/*!!!!!!!!!!!!!!!!!!!!*/
if(ptrint==NULL){
fprintf(stderr,"Error: could not allocate memory for upvec\n");
if(upvec!=NULL) free(upvec);
return 1341;
}else{upvec=ptrint;ptrint=NULL;}
upvec[NREAC-1]=(int *)malloc(DIM*sizeof(int));
if(upvec[NREAC-1]==NULL){
fprintf(stderr,"Error: couldn't get memory for upvec[NREAC-1]\n");
return 1340;
}
for(i=semicolon+1;i<strlen(temp)-1;i++)
temp1[i-semicolon-1]=temp[i];
temp1[i-semicolon-1]='\n';/*Include newline for more convenient way of parsing*/
strcpy(upstr[NREAC-1],temp1);
/*Get update vector*/
upvec[NREAC-1]=process_update_vector(upstr[NREAC-1],upvec[NREAC-1]);
memset(temp1,'\0',STRLEN);
memset(temp,'\0',STRLEN);
continue;
此代码段出现在for循环中。 “无效指针”错误出现在标有/*!!!!!!!!!!!!!!!!!!!!*/
的地方。
错误的条件。足够小DIM
一切正常并且始终有效。在某些时候,我不得不将DIM
增加到11,然后在解析过程中发生错误(通常是错误,我猜,*** glibc detected *** dinamica: realloc(): invalid pointer: 0x000000000165d190 ***
)。 NREAC
的值似乎不影响realloc行为。它始终与发生错误的代码中的位置相同。我是否错误地为int
类型变量分配了内存,因为char
类型的分配从来都不是问题?
process_update_vector
功能:
int * process_update_vector(const char *upstr,int *upvec)
{
int i,j,k;
char symbuf[5];/*5 symbols, max 99999 is possible*/
i = 0;
j = 0;
k = 0;
while(upstr[i] != '\n'){
if(upstr[i] == ','){/*',' is the delimiter*/
symbuf[j] = '\0';
j = 0;
upvec[k] = atoi(symbuf);
k++;
i++;
continue;
}
symbuf[j] = upstr[i];
j++;
i++;
}
/*For the last entry*/
upvec[k] = atoi(symbuf);
k++;
return upvec;
}
答案 0 :(得分:2)
好的,我试着查看你的代码。我的眼睛酸痛,但我设法完成了代码。这里我对第一部分进行了更改,您可以在其中读取冒号和分号之间的表达式。我改变了一些类型,但是让或多或少相同的错误处理,即使我认为它是矫枉过正或更好说,它是在错误的地方(我倾向于将分配/错误工作与业务代码分开,使其更容易调试)。
/*Before this point, current line in the source is read into `temp'*/
char **propstr=NULL; /* I hope this variable was initialized to NULL or else you get problems */
NREAC++; /* This is bad naming, all uppercase is by convention reserved for macros */
char *colon = strchr(temp, ':'); /* There a lib function to do the searching, use them */
char *semicolon = strchr(temp, ';');
if(!colon || !semicolon) {
fprintf(stderr,"Error: syntax error\n");
return 2112; /* whatever */
}
ptrchar=realloc(propstr,NREAC*sizeof(char *)); /* realloc called with a NULL pointer is the same as a malloc, typecasts of mallocs/reallocs are not good. */
if(!ptrchar) {
fprintf(stderr,"Error: could not allocate memory for propstr\n");
free(propstr); /* The check against NULL is also done by free, it's therefoe redundant */
return 1345;
}
else
propstr=ptrchar; /* There's no point in NULLing a variable that will be overwritten anyway */
size_t lenexpr = semicolon-colon; /* The length of the expression can be found by subtracting both pointers */
propstr[NREAC-1]=malloc(lenexpr+1); /* +1 for the \n */
if(!propstr[NREAC-1]) {
fprintf(stderr,"Error: couldn't get memory for propstr[NREAC-1]\n");
return 1344;
}
memcpy(propstr[NREAC-1], colon+1, lenexpr); /* We copy directly without a temporary that way */
propstr[NREAC-1][lenexpr] = '\n'; /* add the linefeed */
propstr[NREAC-1][lenexpr+1] = 0; /* terminate the string */
我在这里停了下来,因为你的第二部分有一个我不明白的根本错误。是否要将矢量存储为字符串或整数数组。如果是前者,则必须分配字符,而不是sizeof (int)
,如果后者必须在某处atoi
或strtol
。
当您向SO提交问题时,还有其他几件事情会很好,您应该包括您使用的变量的声明,您应该显示您使用的宏的定义。
编辑:第二部分
// Edit3 ptrchar=realloc(upstr, NREAC*sizeof(char *));
// Edit3 if(!ptrchar) {
// Edit3 fprintf(stderr,"Error could not allocate memory for upstr\n");
// Edit3 free(upstr);
// Edit3 return 1343;
// Edit3 }
// Edit3 else
// Edit3 upstr=ptrchar;
// Edit3 upstr[NREAC-1] = malloc(strlen(semicolon)+1); /* +1 for the \n */
// Edit3 if(!upstr[NREAC-1]) {
// Edit3 fprintf(stderr,"Error: couldn't get memory for upstr[NREAC-1]\n");
// Edit3 return 1342;
// Edit3 }
if(strlen(semicolon)<2) {/*No vector is specified*/
fprintf(stderr,"Error: no update vector found:\n'%s'", temp);
return 1;
}
ptrint = realloc(upvec, NREAC*sizeof(int *));/*!!!!!!!!!!!!!!!!!!!!*/
if(!ptrint) {
fprintf(stderr,"Error: could not allocate memory for upvec\n");
free(upvec);
return 1341;
}
else
upvec=ptrint;
upvec[NREAC-1] = malloc(DIM*sizeof(int));
if(!upvec[NREAC-1]) {
fprintf(stderr,"Error: couldn't get memory for upvec[NREAC-1]\n");
return 1340;
}
// Edit3 memcpy(upstr[NREAC-1], semicolon+1, strlen(semicolon+1)+1); /* +1 will include the \0 */
// Edit3 strcat(upstr[NREAC-1], "\n"); /*Include newline for more convenient way of parsing*/
/*Get update vector*/
// Edit3 upvec[NREAC-1] = process_update_vector(upstr[NREAC-1], upvec[NREAC-1]);
// Edit3, let's reuse our initial pointer, it's still valid.
process_update_vector(semicolon+1, upvec[NREAC-1]);
continue;
该函数process_update_vector
的签名似乎很奇怪,是否重新分配upvec[NREAC-1]
?如果没有,那么返回并重新分配就没有意义了。因此,显示该功能也是一个好主意。
结论:我在代码中检测到的唯一错误是,由于附加的\ n,分配的长度太短了。
其他要点:通过我的if(first) malloc else realloc
替换realloc
,您必须确保指针最初为NULL,否则您就会遇到问题。
EDIT2:这里是process_update_vector的更新版本,本身并不正确,但它的功能有点复杂。它也有很高的缓冲区溢出风险,临时缓冲区只有5个字符!
此版本不需要临时缓冲区。
void process_update_vector(const char *upstr, int *upvec)
{
const char *p = strchr(upstr, ','); /* There are fine library functions for string handling */
int k = 0;
while(p) {
upvec[k++] = atoi(upstr);
upstr = p+1; /* Position upstr to after , */
p = strchr(upstr, ',');
}
upvec[k++] = atoi(upstr);
/* We don't need to return upvec, it doesn't change in the function */
}
两条评论:
- 没有检查DIM,所以在输入损坏时我们可以有一个缓冲区溢出。
- 没有任何空格处理,通常用逗号后面的空格输入字符串(它更具可读性),这种情况在这种情况下不起作用,但放在正确位置的几个while(*p==' ') p++;
可以处理这一点。
<强> EDIT3:强>
被调用函数的更改也会更改调用者,您无需复制到upstr,因此可以完全删除分配。我在第二个列表中添加了// Edit3
个评论。当然,除非您打算在其他地方重复使用复制的字符串。
PS:在SO上,感谢是通过提升答案来完成的。
答案 1 :(得分:0)
使用Microsoft Visual Studio 2005我将代码粘贴到临时文件中,并使用reformat命令将其重新格式化为以下文本。
请参阅此Wikipedia article on Programming style,它可以帮助您防止堆栈溢出提交。
另见sample of a C coding styles document。
编辑开始
运行时抱怨指针无效,指示您传递给realloc()
的指针不是通过调用malloc()
或calloc()
创建的指针。它知道因为每当你执行malloc()时,都有一个内存管理头,它是数据区的一部分,你给出的指针是一个指向头之后分配的内存的指针。请参阅此问题How does realloc know how much to copy?
最后,我使用state machine approach重写了这一点(另请参阅state machine explanation)并将该源代码放在重新格式化示例的底部。 编辑结束
查看源代码,这似乎是循环的一部分。似乎变量upvec可能没有初始化,它是某种类型的数组,所以它实际上是malloced还是没有?
请参阅显示//--------------------
的部分。
重新格式化的来源如下:
/*Before this point, current line in the source is read into `temp'*/
NREAC++;
for(i=0;i<strlen(temp);i++){
if(temp[i]==':') colon=i;//Here we find colon
if(temp[i]==';') semicolon=i;//...and semicolon positions
}
memset(temp1,'\0',STRLEN);
if(NREAC==1)
ptrchar=(char **)malloc(sizeof(char *));
else
ptrchar=realloc(propstr,NREAC*sizeof(char *));
if(ptrchar==NULL){
fprintf(stderr,"Error: could not allocate memory for propstr\n");
if(propstr!=NULL) free(propstr);
return 1345;
} else {
propstr=ptrchar;
ptrchar=NULL;
}
propstr[NREAC-1]=(char *)malloc((semicolon-colon)*sizeof(char));
if(propstr[NREAC-1] == NULL){
fprintf(stderr,"Error: couldn't get memory for propstr[NREAC-1]\n");
return 1344;
}
for(i=colon+1;i<semicolon;i++)/*Copy the propensity part of the line*/
temp1[i-colon-1]=temp[i];
temp1[i-colon-1]='\n';/*Include newline symbol for correct parsing*/
strcpy(propstr[NREAC-1],temp1);
memset(temp1,'\0',STRLEN);
if(NREAC==1)
ptrchar=(char **)malloc(sizeof(char *));
else
ptrchar=realloc(upstr,NREAC*sizeof(char *));
if(ptrchar==NULL){
fprintf(stderr,"Error could not allocate memory for upstr\n");
if(upstr!=NULL) free(upstr);
return 1343;
} else {
upstr=ptrchar;
ptrchar=NULL;
}
upstr[NREAC-1]=(char *)malloc((strlen(temp)-semicolon-1)*sizeof(char));
if(upstr[NREAC-1]==NULL){
fprintf(stderr,"Error: couldn't get memory for upstr[NREAC-1]\n");
return 1342;
}
if(strlen(temp)-semicolon==2){/*No vector is specified*/
fprintf(stderr,"Error: no update vector found:\n");
fprintf(stderr,"`%s'",temp);
return 1;
}
// -----------------------------------------------------
if(NREAC==1)
ptrint=(int **)malloc(sizeof(int *));
else
ptrint=(int **)realloc(upvec,NREAC*(sizeof(int *)));/*!!!!!!!!!!!!!!!!!!!!*/
if(ptrint==NULL){
fprintf(stderr,"Error: could not allocate memory for upvec\n");
if(upvec!=NULL) free(upvec);
return 1341;
} else {
upvec=ptrint;
ptrint=NULL;
}
upvec[NREAC-1]=(int *)malloc(DIM*sizeof(int));
if(upvec[NREAC-1]==NULL){
fprintf(stderr,"Error: couldn't get memory for upvec[NREAC-1]\n");
return 1340;
}
// ---------------
for(i=semicolon+1;i<strlen(temp)-1;i++)
temp1[i-semicolon-1]=temp[i];
temp1[i-semicolon-1]='\n';/*Include newline for more convenient way of parsing*/
strcpy(upstr[NREAC-1],temp1);
/*Get update vector*/
upvec[NREAC-1]=process_update_vector(upstr[NREAC-1],upvec[NREAC-1]);
memset(temp1,'\0',STRLEN);
memset(temp,'\0',STRLEN);
continue;
修改强> 使用具有将解析每行文本的函数的状态机的建议方法。
#include <malloc.h>
#include <stdlib.h>
// pLine is a line of text containing a zero terminated string of the format of
// g:<expression>;0,1,0,1,0
// This function will process the line and return the expression as a string
// and a list of the integers.
void processExpression (char *pLine, char *pExpression, int **pIntList)
{
int stateMachineIndex = 1;
int integerCount = 0;
char *pLineSave = 0;
int iIntListIndex = 0;
*pIntList = 0;
while (*pLine) {
switch (stateMachineIndex) {
case 1:
// initial state
if (*pLine == ':') {
// colon found so now start getting the expression
stateMachineIndex = 2;
}
pLine++;
break;
case 2:
if (*pLine != ';') {
*pExpression++ = *pLine++;
} else if (*pLine) {
// if we have not reached end of string yet then go to the
// next state of parsing the list of integers.
stateMachineIndex = 3;
pLine++;
pLineSave = pLine;
}
break;
case 3:
// at this point we begin to process the list of integers.
// however we are not sure how many there are so we will count them first
if (*pLine == ',') {
integerCount++;
}
pLine++;
break;
case 4:
// we now have a count of the integers we expect however it
// may be off by one so we will allocate a smidge more space
*pIntList = (int *)calloc ((integerCount + 2), sizeof(int));
stateMachineIndex = 5;
*pExpression = 0; // and while we are at it lets terminate our expression string
break;
case 5:
// now we get an integer value from the list of integers
(*pIntList)[iIntListIndex++] = atoi (pLine);
// eat up characters to the next integer in the list
while (*pLine && *pLine != ',') pLine++;
if (*pLine == ',') pLine++; // if we found a comma, skip it to the next field
break;
default:
break;
}
if (*pLine == 0 && stateMachineIndex < 4) {
// end of the string so now lets do our integer thing
// if we are still in the first phase of processing
if (pLineSave && *pLineSave && integerCount > 0) {
stateMachineIndex = 4;
pLine = pLineSave; // restart our parser back to the integer area
} else {
break;
}
}
}
}
// simple test harness to test the concept.
int main(int argc, char* argv[])
{
char *pLine = "g:expression and stuff;1,2,3,4,5";
char expressionBuffer[128];
int *pIntList = 0;
processExpression (pLine, expressionBuffer, &pIntList);
return 0;
}