2014-10-06 3 views
1

Я использую код ANSI C, созданный из генератора кода, который создает несколько слоев вложенных struct, а также прототипы функций с списками аргументов, которые используют указатели для верхний слой struct для передачи или доступа к данным, расположенным во внутренней mmost struct.ANSI C Распределение памяти для указателя на struct throws нефатальная ошибка во время выполнения

Поскольку прототипы функций передают указатели на struct, приложение должно выделять память для доступа или записи данных во внутренние элементы структуры. Я вижу проблему при попытке выделить память для указателя на вторую вложенную структуру.

Фактическое сообщение об ошибке, которое я получаю, является нефатальным временем выполнения: «Недостаточно места для выражения выражения для« указателя на данные структуры ».

Я не явным образом бросаю что-нибудь, поэтому я подозреваю, что реализация malloc() может иметь утверждение, которое генерирует сообщение, когда оно видит какое-то условие. Формулировка этой ошибки может быть специфичной для моей среды (я использую LabWindows/CVI), но мне было бы интересно услышать результаты других компиляторов ANSI C.

Вот упрощенный, полный, фрагмент кода, который должен собрать, построить и запустить (до места ошибки, который комментировал в линию)

Я был бы признателен комментарии о причине моей ошибки, и предложения по его устранению.

#include <ansi_c.h> //specific to LabWindows/CVI - change as needed for your environment 

struct request 
{ 
    struct data *pData; 
}; 

struct data 
{ 
    char *wsDate; 
    char *wsDuration; 
    char *wsFailures; 
    int __sizeM_Details;  
    struct details *M_Details; 
}; 


struct details 
{ 
    char *wsStep; 
    char *wsTestDesc; 
    char *wsLowLim; 
}; 

typedef struct request REQUEST; // from mtdf function prototype request argument (4) 
typedef struct details DETAILS; // member of REQUEST - _ns1__MTDFData_MTDFDetail 

void allocate(REQUEST *a, int numRecords); 
void freemem(REQUEST *c, int numRecords); 

int main(void) 
{ 
    REQUEST b, *pB; 

    pB = &b; 

    allocate(pB, 10); 
    freemem(pB, 10); 
    return 0; 
} 

void allocate(REQUEST *c, int numRecords) 
{ 
    DETAILS m_Param; 
    REQUEST b; 
    struct data d; 

    size_t size_c = sizeof(c); 
    c = malloc(size_c); //4 bytes 

    size_t size_c_data = sizeof(c->pData); 
    c->pData = malloc(size_c_data); //Breaks here - this is just a pointer, 
            //should it not just allocate 4 bytes 
            //and continue? 
    // Actual error message: 
    // "Not enough space for casting expression to 'pointer to struct data'." 
    c->pData->wsDate = calloc(80, sizeof(char)); 

    c->pData->__sizeM_Details = numRecords; 
    c->pData->M_Details = calloc((numRecords + 1) , sizeof(m_Param)); 

} 

void freemem(REQUEST *c, int numRecords) 
{ 
    free(c->pData->M_Details); 
    free(c->pData->wsDate); 
    free(c->pData); 
    free(c); 
} 
+0

К сожалению, я должен немного отойти от своего стола, так что, если кто-то задаст вопрос относительно этого сообщения, я не игнорирую вас У, я вернусь, как только смогу, завтра в худшем случае. – ryyker

+2

Вы должны выделить достаточно места для хранения 'struct data', а не' struct data * '. Аналогичным образом, вы должны выделить достаточно памяти для хранения 'REQUEST', а не' REQUEST * '. –

+0

Как T.C. говорит, что во время выполнения вам сообщается, что вы не выделяете достаточное пространство для того, для чего объявляется 'c-> pData'. См. Http://zone.ni.com/reference/en-XX/help/370051M-01/cvi/programmerref/pointercastingnonfatal/ –

ответ

3

Там в нескольких фундаментальных проблемах, здесь:

  1. В allocate(), все, что память вы malloc() ИНГОВ теряются в конце вашей функции, потому что вы присваиваете его к локальная переменная, c, которая уничтожается в конце вашей функции. Вы никогда не используете адрес структуры с автоматическим временем хранения, который вы передаете в функцию. Если вы передаете адрес объекта с автоматической продолжительностью хранения, то для членов должны быть malloc() памяти, но не для самой структуры, поскольку она, очевидно, уже имеет память.

  2. Затем, в freemem(), вы пытаетесь установить память, связанную с b, которая представляет собой структуру с автоматическим временем хранения. Вы можете только free() памяти, которую вы динамически выделили.

  3. У вас есть любопытный комментарий в allocate(), «это всего лишь указатель, если он не просто выделит 4 байта и продолжит?». Если вы находитесь в системе с 32-битными указателями, то это действительно то, что вы выделили, но c->pData является указателем на struct data, который выглядит так, как будто ему нужно 28 байт на 32-битной машине, поэтому вы должны выделять намного больше, чем 4 байтов для него. Линии вроде c->pData->wsDate = ..., похоже, указывают, что вы хорошо знаете, что это указатель на struct data, так что действительно непонятно, почему вы думаете, что вам нужно всего лишь выделить 4 байта. Когда вы выделяете память для ANYTHING *, чтобы указать на то, вам нужно выделить достаточное количество памяти для ANYTHING, а не для ANYTHING *, то есть достаточно памяти для того, что она будет указывать на. Тот факт, что вы пытаетесь назначить память вашему указателю, в первую очередь доказывает, что у вас уже есть память для вашего указателя, иначе вы не сможете этого сделать (при условии, что вы не испортили предыдущий выделение, конечно).

  4. Вы никогда не проверяете возврат с malloc() и calloc(), и вам следует.

  5. Имена, начинающиеся с двойного подчеркивания, всегда зарезервированы для реализации, поэтому вы должны позвонить __sizeM_Details что-то еще.

  6. sizeof(char) по определению 1, поэтому его никогда не нужно использовать.

  7. Неясно, почему вы выделения памяти для numRecords + 1 вашего struct details, а не просто numRecords, как казалось бы интуитивно. Возможно, вы хотите установить последнее значение NULL в качестве значения контрольной суммы, но если вы уже храните количество записей в своей структуре, то это действительно не обязательно.

Вот что ваш код должен выглядеть следующим образом:

#include <stdio.h> 
#include <stdlib.h> 

struct request { 
    struct data * pData; 
}; 

struct data { 
    char * wsDate; 
    char * wsDuration; 
    char * wsFailures; 
    int sizeM_Details;  
    struct details * M_Details; 
}; 

struct details { 
    char * wsStep; 
    char * wsTestDesc; 
    char * wsLowLim; 
}; 

typedef struct request REQUEST; 
typedef struct details DETAILS; 

void allocate(REQUEST * c, const int numRecords); 
void freemem(REQUEST * c); 

int main(void) 
{ 
    REQUEST b; 
    allocate(&b, 10); 
    freemem(&b); 
    return 0; 
} 

void allocate(REQUEST * c, const int numRecords) 
{ 
    if (!(c->pData = malloc(sizeof *c->pData))) { 
     perror("couldn't allocate memory for c->pData"); 
     exit(EXIT_FAILURE); 
    } 

    if (!(c->pData->wsDate = calloc(80, 1))) {  
     perror("couldn't allocate memory for c->pData->wsDate"); 
     exit(EXIT_FAILURE); 
    } 

    if (!(c->pData->M_Details = calloc(numRecords + 1, 
             sizeof(*c->pData->M_Details)))) { 
     perror("couldn't allocate memory for c->pData->M_Details"); 
     exit(EXIT_FAILURE); 
    } 

    c->pData->sizeM_Details = numRecords; 
} 

void freemem(REQUEST * c) 
{ 
    free(c->pData->M_Details); 
    free(c->pData->wsDate); 
    free(c->pData); 
} 

Если выделение автоматического хранения для b была ошибка, и вы действительно хотите, чтобы динамически выделять все, в том числе ваш struct request, то он должен выглядят так:

#include <stdio.h> 
#include <stdlib.h> 

struct request { 
    struct data * pData; 
}; 

struct data { 
    char * wsDate; 
    char * wsDuration; 
    char * wsFailures; 
    int sizeM_Details;  
    struct details * M_Details; 
}; 

struct details { 
    char * wsStep; 
    char * wsTestDesc; 
    char * wsLowLim; 
}; 

typedef struct request REQUEST; 
typedef struct details DETAILS; 

REQUEST * allocate(const int numRecords); 
void freemem(REQUEST * c); 

int main(void) 
{ 
    REQUEST * b = allocate(10); 
    freemem(b); 
    return 0; 
} 

REQUEST * allocate(const int numRecords) 
{ 
    REQUEST * c = malloc(sizeof *c); 
    if (!c) { 
     perror("couldn't allocate memory for c"); 
     exit(EXIT_FAILURE); 
    } 

    if (!(c->pData = malloc(sizeof *c->pData))) { 
     perror("couldn't allocate memory for c->pData"); 
     exit(EXIT_FAILURE); 
    } 

    if (!(c->pData->wsDate = calloc(80, 1))) { 
     perror("couldn't allocate memory for c->pData->wsDate"); 
     exit(EXIT_FAILURE); 
    } 

    if (!(c->pData->M_Details = calloc(numRecords + 1, 
             sizeof(*c->pData->M_Details)))) { 
     perror("couldn't allocate memory for c->pData->M_Details"); 
     exit(EXIT_FAILURE); 
    } 

    c->pData->sizeM_Details = numRecords; 

    return c; 
} 

void freemem(REQUEST * c) 
{ 
    free(c->pData->M_Details); 
    free(c->pData->wsDate); 
    free(c->pData); 
    free(c); 
} 
+0

Я ценю детали, которые вы предоставили. Основной проблемой для меня и той, которая решила мою проблему, является строка 'c-> pData = malloc (sizeof * c-> pData)'. Некоторые из проблем, которые вы указываете (4,5,6,7), являются либо артефактами упрощения примера к соответствующим проблемам, либо являются соглашениями об именах, используемыми генератором кода и т. Д. Точки 1,2 и 3 адресуют реальные проблемы Что ж. Спасибо. – ryyker