-9

再び再割り当ての問題です。以前の多くの realloc ステートメントで同様の問題を見つけることができなかったようです。ご関心をお寄せいただければ幸いです。

次の形式のテキスト入力を読み込もうとしています: g:<expression>;0,1,0,1,0. ソース テキスト ファイルにはこの形式の一連の行があり、"for" ループでこの行を読み取るコードのスニペット (以下) があります。との間のが2D char 配列に読み込まれます。以降はすべて、コンマで区切られた数値のベクトル (サイズ) を決定します。このベクトルは (文字列として) に読み込まれ、関数によって整数の配列に変換されます。ループの反復ごとに、前述の配列 ( 、および) のサイズを調整するために使用されます。ループでこれまでに読み取られた行数は です。コードは次のとおりです。:;propstr;DIM,upstrupvecprocess_update_vectorreallocpropstrupstrupvecNREAC

/*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、すべてが正常に機能し、常に機能します。ある時点で、DIM11 まで増やす必要があり、解析手順の途中でエラーが発生しました (通常のエラーだと思います*** glibc detected *** dinamica: realloc(): invalid pointer: 0x000000000165d190 ***)。の値はNREAC、再割り当ての動作に影響していないようです。エラーが発生するコード内の場所は常に同じです。型の割り当ては決して問題ではなかった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;
}
4

2 に答える 2

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 */

2 番目の部分に、理解できない根本的な誤りがあるため、ここで停止しました。ベクトルを文字列として保存しますか、それとも整数配列として保存しますか。前者の場合は char ではなく char を割り当てる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その他のポイント:を myに置き換えることにより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 */
}

2 つのコメント: - DIM のチェックがないため、壊れた入力でバッファ オーバーフローが発生する可能性があります。- 空白の処理はありません。多くの場合、文字列はコンマの後にスペースを入れて入力されます (読みやすくなります) while(*p==' ') p++;

EDIT3: 呼び出された関数の変更により、呼び出し元も変更されます。upstrにコピーする必要がないため、割り当てを完全に削除できます。// Edit32番目のリストにコメントを追加しました。もちろん、コピーした文字列を他の場所で再利用する場合を除きます。

PS: SO では、感謝は回答に賛成票を投じることによって行われます。

于 2012-10-25T08:33:08.343 に答える
0

Microsoft Visual Studio 2005を使用して、コードを一時ファイルに貼り付け、reformatコマンドを使用して以下のテキストに再フォーマットしました。

プログラミングスタイルに関するこのウィキペディアの記事を参照してください。これは、stackoverflowの送信で炎上するのを防ぐのに役立ちます。

Cコーディングスタイルドキュメントのこのサンプルも参照してください。

EDIT beginランタイムは、渡しているポインターがへのまたはへrealloc()の呼び出しで作成されたポインターではない ことを示す無効なポインターについて文句を言っています。これは、malloc()を実行するたびに、データ領域の一部であるメモリ管理ヘッダーがあり、指定されたポインターは、ヘッダーの後に割り当てられたメモリーへのポインターであるためです。この質問を参照してくださいreallocはどのようにコピーする量を知っていますか?malloc()calloc()

最後に、ステートマシンアプローチステートマシンの説明も参照)を使用してこれを書き直し、そのソースコードを再フォーマットされた例の下部に配置しました。 編集終了

ソースを見ると、これはループの一部であるように見えます。変数upvecが初期化されていない可能性があり、それはある種の配列であるため、実際にmallocされているかどうか。

//--------------------示されたセクションを参照してください。

再フォーマットされたソースは次のとおりです。

    /*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;
}
于 2012-10-24T12:53:41.880 に答える