2012-11-17 20 views
6

Tôi khá là khao khát về một lỗi mà tôi không thể vượt qua được.Tại sao malloc trả về NULL với nhiều bộ nhớ và luôn ở cùng một điểm?

Đối với lớp lập trình C của tôi ở trường đại học, tôi phải triển khai trình phân tích cú pháp cho luồng đầu vào GML (Graph Modeling Language).

Khi thành công, trình phân tích cú pháp trả về một kiểu dữ liệu trừu tượng cho người gọi, là một ma trận adjacency như là biểu diễn của biểu đồ.

Được rồi, trình phân tích cú pháp hoạt động hoàn hảo, sẽ không có vấn đề gì làm tôi thất vọng trong vài ngày qua. Trong trình phân tích cú pháp, có một cuộc gọi hàm mà lần lượt gọi malloc. malloc được gọi khá thường xuyên trong khi máy quét cung cấp biểu tượng bằng ký hiệu cho trình phân tích cú pháp. Nhưng khối malloc´d mem luôn luôn được giải phóng bằng cách gọi free() trước khi rời khỏi thói quen quét.

Nhưng có một hàm chết gọi khá sâu bên trong trình phân tích cú pháp, mà lần lượt gọi hàm sử dụng malloc để đặt trước 12 byte bộ nhớ (ba thuộc tính nguyên) để lưu cấu trúc. Cấu trúc là cần thiết để lưu trữ thông tin về một cạnh duy nhất trong biểu đồ (nút nguồn, nút đích, trọng số).

Cuộc gọi này được thực hiện hai lần. lần đầu tiên, mọi việc suôn sẻ. Sau đó, vì có thể xảy ra 1 đến n cạnh theo cú pháp gml, mã sẽ nhập vào một vòng lặp while, trong đó cùng một con trỏ được gán với một con trỏ tới một Edge Struct mới, miễn là có các Edges được tìm thấy trong luồng đầu vào. Cuộc gọi đầu tiên của thủ tục nhận dạng Edge trong vòng lặp, đó là lần thứ hai trong tổng số (lần đầu tiên xảy ra trước khi vào vòng lặp, xem m.a.), không liên tục bởi malloc trả về NULL.

Tôi đơn giản không biết tại sao.

Nó không phải về vấn đề thiếu bộ nhớ, bởi vì khi tôi malloc 1000 byte trong hàm main() của chương trình đó, chỉ để cho vui, nó hoạt động tốt.

Tôi sử dụng Mã :: Blocks và DevCPP làm IDE. Trong cả hai, chương trình gặp phải cùng một vấn đề.

Here's thói quen của tôi chính phân tích:

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; 
} 

}

Ở đây GetNextSymbol (máy quét, mang lại những biểu tượng để phân tích cú pháp):

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

} 

và bây giờ cuộc gọi gây tử vong trong thói quen nhận dạng "Edge". Thứ nhất, tiêu đề cho struct

#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 

Việc thực hiện

#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; 
} 

tôi biết, that's khá nhiều mã;) Chỉ cần để hiển thị, rằng tất cả những gì có thể được trả tự do, tôi giải phóng.

Tôi googled vấn đề của tôi trong hai ngày qua, tất nhiên cũng ở đây tại ngăn xếp tràn, và có hàng trăm trang web, bài đăng et cetera liên quan đến malloc trở về null. Tất cả họ đều nói về cơ bản giống nhau: không đủ bộ nhớ (có nghĩa là, cho phép gọi nó là không), hoặc đống phân mảnh, do đó, không có khối nhớ đủ kích thước có sẵn.

nhưng: tất cả tôi yêu cầu là 12 (bằng chữ: mười hai) byte để lưu trữ ba thuộc tính int. dường như quá nhiều.

Tôi đã vượt quá một số giới hạn nội bộ mà tôi không biết?

Trợ giúp sẽ được đánh giá cao.

Cảm ơn trước Roland

EDIT 2012/11/24:

cảm ơn vì câu trả lời của bạn. nhưng. vấn đề phải có tính chất cơ bản hơn.

vì: khi tôi kiểm tra các phần khác của chương trình (tệp I/O), v.v. ít phức tạp hơn trình phân tích cú pháp và chỉ thực hiện một cuộc gọi sâu từ chính(), tôi cũng không thể malloc. Tập tin tôi đọc có khoảng 140 byte. Ngay cả khi tôi kiểm tra phần I/O được phân lập từ tất cả các phần khác, ngay cả khi tôi thuê ngoài chúng trong một dự án khác, tôi không nhận được bộ nhớ nào từ hệ thống. không có nghĩa là. Tôi đã khởi động lại máy tính, mọi thứ. chắc chắn rồi. Không. thay đổi.

bất kỳ ý tưởng nào? trong khi chờ đợi tôi đã bỏ quá nhiều giờ trong dự án này, phần lớn trong số đó đang theo dõi các lỗi bộ nhớ đó ...: - (((

+7

Bạn có chắc chắn rằng vấn đề là về malloc trở về NULL? Điều này là rất hiếm, thay vào đó có thể xảy ra mà bạn đôi miễn phí một con trỏ. Cố gắng để khẳng định rằng malloc không bao giờ trả về NULL. –

+7

Bạn đã thử Valgrind chưa? –

Trả lời

1

Tôi không thể nói nhiều, chỉ một quan sát. trong GetNextSymbol(), tôi thấy không có hạn chế về số lượng chữ số đọc, vì vậy có khả năng xảy ra một lỗi tràn bộ đệm. cũng vậy với đọc một định danh.

một số khác trong Graph(), những thất bại Edge(sourceString, currentPosition) gọi là trong một

3

Nếu bạn nghi ngờ bạn áp dụng việc sử dụng quá nhiều bộ nhớ hoặc phân mảnh tất cả bộ nhớ có sẵn thì bạn có thể kiểm tra việc sử dụng bộ nhớ bằng ứng dụng của bạn trong khi chạy. Nếu nó ăn tất cả bộ nhớ hệ thống thì malloc trả về NULL vì điều này.

Nếu trường hợp trên không phải là trường hợp của bạn thì tôi sẽ kiểm tra đơn đăng ký tham nhũng của bạn. Thông thường khi bạn ghi đè lên cấu trúc heap những điều rất xấu xảy ra. Trong trình biên dịch chế độ gỡ lỗi thêm một số kiểm tra thêm và vùng màu đỏ để phát hiện tham nhũng đống. Trong chế độ phát hành phá vỡ cấu trúc heap thường dẫn đến vi phạm truy cập. Tôi có thể tưởng tượng rằng trong trường hợp rất hiếm heap cấu trúc có thể bị hư hỏng và thiệt hại có thể được giải thích là ra khỏi không gian để NULL được trả lại bởi malloc.

Cách này hay cách khác, tôi sẽ sử dụng trình gỡ rối bộ nhớ. Valgrind đã cứu tôi nhiều lần, nhưng nó có thể không có sẵn trong môi trường của bạn. Có rất nhiều chủ đề ở đây trên stackoverflow về bộ nhớ gỡ rối.