私は私が乗り越えることができないエラーにかなり絶望的です。
大学のCプログラミングクラスでは、GML(Graph Modeling Language)入力ストリームのパーサーを実装する必要がありました。
成功すると、パーサーは抽象データ型を呼び出し元に返します。これは、グラフの表現としての隣接行列です。
さて、パーサーは完璧に機能します。ここ数日で私を絶望させる問題はないでしょう。パーサーには、mallocを呼び出す関数呼び出しが1つあります。mallocは、スキャナーがシンボルごとにパーサーに配信するときに頻繁に呼び出されます。ただし、mallocのmemチャンクは、スキャナールーチンを終了する前にfree()を呼び出すことによって常に解放されます。
しかし、パーサーの非常に深いところに致命的な関数呼び出しが1つあります。これは、mallocを使用して構造体を保存するために12バイトのメモリ(3つの整数プロパティ)を予約する関数を呼び出します。構造体は、グラフ内の単一のエッジに関する情報(ソースノード、ターゲットノード、重み)を格納するために必要です。
この呼び出しは2回行われます。初めて、すべてがうまくいきます。次に、gml構文に従って1〜n個のエッジが発生する可能性があるため、コードはwhileループに入ります。ここで、入力ストリームにエッジが見つかっている限り、同じポインターに新しいEdgeStructへのポインターが割り当てられます。ループ内のエッジ認識ルーチンの最初の呼び出しは、合計で2番目です(最初の呼び出しはループに入る前に発生します。maを参照)。mallocがNULLを返すことにより、常に失敗します。
理由がわからない。
それはメモリ不足の問題ではありません。なぜなら、そのプログラムのmain()関数で1000バイトをmallocすると、楽しみのために、正常に動作するからです。
IDEとしてCode::BlocksとDevCPPを使用しています。どちらの場合も、プログラムで同じ問題が発生します。
これが私の主な解析ルーチンです。
DirectedGraph Graph(char* sourceString, int*currentPosition){
int sym;
int restartPosition = 0;
int* backupPosition;
char* backupString;
int nodeCount = 0;
int currentSrc = -1;
int currentTgt = -1;
int currentWgt = -1;
EdgeDescription e;
DirectedGraph correctMatrix;
MatrixStruct* errorMatrix = NULL;
/*begin parsing*/
bool isGraphHeader = GraphHdr(sourceString, currentPosition);
if(isGraphHeader == true){
bool isNode = Node(sourceString, currentPosition);
if(isNode == true){
while(isNode == true){
nodeCount++;
restartPosition = *currentPosition;
isNode = Node(sourceString, currentPosition);
}
*currentPosition = restartPosition;
/*now get edge information (from-to-weight)*/
/*as we have already read the next symbol, we have to reset*/
/*our read position by one symbol backwards*/
e = Edge(sourceString, &restartPosition); /*<======== HERE I CALL THE FATAL ROUTINE FOR THE FIRST TIME - EVERYTHING´s JUST FINE, PROGRAM PROCEEDS*/
restartPosition = 0;
/*just for clearer coding in if statement*/
currentSrc = e->source;
currentTgt = e->target;
currentWgt = e->weight;
destroyEdge(e);
if(currentSrc != -1 && currentTgt != -1 && currentWgt != -1){
/*initialize matrix with counted number of nodes*/
correctMatrix = CreateNewGraph(nodeCount);
/*the edge is inserted only when it lies within the boundaries*/
/*of our graph. but we do not interrupt the whole processing, we just skip it.*/
while(currentSrc != -1 && currentTgt != -1 && currentWgt != -1){
if(currentSrc <= nodeCount && currentTgt <= nodeCount){
InsertEdge(correctMatrix, currentSrc, currentTgt, currentWgt);
restartPosition = *currentPosition;
}
e = Edge(sourceString, currentPosition); /* <============== THIS IS THE CALL THAT FAILS*/
currentSrc = e->source;
currentTgt = e->target;
currentWgt = e->weight;
}
/*as we have read over the next symbol in the loop, reset the position to read*/
*currentPosition = *currentPosition - 1;
sym = GetNextSymbol(sourceString,currentPosition);
if(sym == rightBrace){
sym = GetNextSymbol(sourceString, currentPosition);
if(sym == eot){
return correctMatrix;
}
else{
return errorMatrix;
}
}
else{
return errorMatrix;
}
}
else{
return errorMatrix;
}
}
else{
return errorMatrix;
}
}
else{
return errorMatrix;
}
}
ここで、GetNextSymbol(シンボルをパーサーに配信するスキャナー):
/**
* DOCUMENTATION
* ============================
* This is the main scanning function
* which is used by the parser to recognize
* terminal symbols and valid literals.
*
* RETURNS: the enum code for the recognized symbol.
* or an error code, when invalid symbol encountered.
*/
int GetNextSymbol(char* sourceString, int* currentPosition){
int symbolCode;
int loopCounter = 0;
char* currentIdentifier = (char*)malloc(10);
char* currentNumber = (char*)malloc(10);
int identifierPosition = 0;
int numberPos = 0;
int numericVal = 0;
char currentChar;
currentChar = getNextChar(sourceString, currentPosition);
/*skip all blanks, empty chars,
linefeeds, carriage returns*/
while(currentChar == ' '
|| currentChar == 11
|| currentChar == 10
|| currentChar == 13
|| currentChar == '\t')
{
currentChar = getNextChar(sourceString, currentPosition);
}
/*=====================================*/
/*Section 1: scan for terminal symbols */
/*====================================*/
if(currentChar == '['){
symbolCode = leftBrace;
}
else if(currentChar == ']'){
symbolCode = rightBrace;
}
/*=====================================*/
/*Section 2: scan for valid literals */
/*====================================*/
else if(isdigit(currentChar)){
/*here we calculate the numeric value of a number expression*/
/*when calculated, we assign the numeric value to the symCode variable*/
/*this works out because the values for a real symbol are always negative*/
symbolCode = digit;
while(isdigit(currentChar)){
currentNumber[numberPos] = currentChar;
currentChar = getNextChar(sourceString, currentPosition);
loopCounter++;
numberPos++;
}
currentNumber[numberPos] = '\0';
numericVal = atoi(currentNumber);
symbolCode = numericVal;
/*when identifier or braces follow number without space: reset currentPos*/
/*to the position of the previous char*/
if(isalpha(currentChar)){
*currentPosition = *currentPosition - loopCounter;
}
else if(currentChar == ']'){
*currentPosition = *currentPosition - loopCounter;
}
else if(currentChar == '['){
*currentPosition = *currentPosition - loopCounter;
}
}
else if(isalpha(currentChar)){
while(isalpha(currentChar)){
currentIdentifier[identifierPosition] = currentChar;
currentChar = getNextChar(sourceString, currentPosition);
loopCounter++;
identifierPosition++;
}
/*check wether we have found a valid identifying label*/
/*and deallocate the reserved mem space*/
currentIdentifier[identifierPosition] = '\0';
symbolCode = recognizeIdentifier(currentIdentifier);
/*when number or braces follow identifier without space: reset currentPos*/
/*to the position of the previous char*/
if(isdigit(currentChar)){
*currentPosition = *currentPosition - 1;
}
else if(currentChar == ']'){
*currentPosition = *currentPosition - 1;
}
else if(currentChar == '['){
*currentPosition = *currentPosition - 1;
}
}
else if(currentChar=='\0'){
symbolCode = eot;
}
/*neither terminal symbol nor end of text found on current position --> illegal symbol*/
else{
symbolCode = error;
}
free(currentIdentifier);
free(currentNumber);
return symbolCode;
}
そして今、「エッジ」認識ルーチンの致命的な呼び出し。まず、構造体のヘッダー
#ifndef GML_EDGE_STRUCT_H_INCLUDED
#define GML_EDGE_STRUCT_H_INCLUDED
typedef struct EdgeStruct* EdgeObj;
typedef struct EdgeStruct {
int source;
int target;
int weight;
} EdgeStruct;
typedef EdgeObj EdgeDescription;
EdgeDescription createNewEdge(int src, int tgt, int wgt);
void destroyEdge(EdgeObj);
#endif // GML_EDGE_STRUCT_H_INCLUDED
実装
#include "GML_EDGE_STRUCT.h"
#include <stdio.h>
#include <stdlib.h>
EdgeDescription createNewEdge(int source, int target, int weight){
EdgeDescription e;
int bytesRequested = sizeof(EdgeStruct);
e = malloc(bytesRequested);
e->source = source;
e->target = target;
e->weight = weight;
return e;
}
私は知っています、それはほとんどコードです;)ただ示すために、解放できるすべてのもの、私は解放しました。
私は過去2日間、もちろんここでもスタックオーバーフローで問題をグーグルで検索しました。そして、mallocがnullを返すことに関する何百ものサイト、投稿などがあります。それらはすべて基本的に同じことを言います:十分なメモリがない(つまり、それをありそうもないと呼ぶことができます)、または断片化されたヒープなので、十分なサイズのmemチャンクは利用できません。
しかし:私が要求するのは、3つのintプロパティを格納するための12(つまり、12)バイトだけです。多すぎるようです。
知らない内部制限を超えましたか?
助けていただければ幸いです。
よろしくお願いしますローランド
2012年11月24日編集:
あなたの答えに感謝します。しかし。問題はもっと基本的な性質のものでなければなりません。
理由:パーサーよりもはるかに複雑ではなく、main()から1回だけ呼び出すプログラムの他の部分(ファイルI / O)などをテストした場合、mallocもできません。私が読んだファイルはおよそ140バイトです。他のすべてのパーツから分離されたI/Oパーツをテストする場合でも、別のプロジェクトでそれらをアウトソーシングする場合でも、システムからメモリを取得しません。決して。私はコンピュータを再起動しました、すべて。絶対。番号。変化する。
何か案は?その間、私はこのプロジェクトにあまりにも多くの時間を費やしましたが、そのほとんどはそれらのf ***ingメモリエラーを追跡しています...:-(((