Основной вопрос C, касающийся распределения памяти и присвоения значений - PullRequest
2 голосов
/ 13 июня 2010

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

Итак, у меня есть действительно базовая модель базы данных: таблицы, кортежи, атрибуты, и я пытаюсь загрузить некоторые данные в эту структуру.Ниже приведены определения:

typedef struct attribute
{
    int type;
    char * name;
    void * value;
} attribute;

typedef struct tuple
{
    int tuple_id;
    int attribute_count;
    attribute * attributes;
} tuple;

typedef struct table
{
    char * name;
    int row_count;
    tuple * tuples;
} table;

Данные поступают из файла со вставками (созданного для теста Висконсина), который я анализирую.У меня есть только целочисленные или строковые значения.Пример строки будет выглядеть так:

insert into table values (9205, 541, 1, 1, 5, 5, 5, 5, 0, 1, 9205, 10, 11, 'HHHHHHH', 'HHHHHHH', 'HHHHHHH');

Мне «удалось» загрузить и проанализировать данные, а также назначить их.Однако бит присваивания содержит ошибки, поскольку все значения указывают на одну и ту же область памяти, то есть все строки выглядят одинаково после того, как я загрузил данные.Вот что я делаю:

char value[10]; // assuming no value is longer than 10 chars
int i, j, k;

table * data = (table*) malloc(sizeof(data));
data->name = "table";
data->row_count = number_of_lines;
data->tuples = (tuple*) malloc(number_of_lines*sizeof(tuple));

tuple* current_tuple;

for(i=0; i<number_of_lines; i++)
{
    current_tuple = &data->tuples[i];
    current_tuple->tuple_id = i;
    current_tuple->attribute_count = 16; // static in our system
    current_tuple->attributes = (attribute*) malloc(16*sizeof(attribute));

    for(k = 0; k < 16; k++)
    {
        current_tuple->attributes[k].name = attribute_names[k];

        // for int values:
        current_tuple->attributes[k].type = DB_ATT_TYPE_INT;
        // write data into value-field
        int v = atoi(value);
        current_tuple->attributes[k].value = &v;

        // for string values:
        current_tuple->attributes[k].type = DB_ATT_TYPE_STRING;
        current_tuple->attributes[k].value = value;
    }

    // ...
}

Хотя я прекрасно понимаю, почему это не работает, я не могу понять, как заставить это работать.Я пробовал следующие вещи, ни один из которых не работал:

 memcpy(current_tuple->attributes[k].value, &v, sizeof(int));

Это приводит к ошибке плохого доступа.То же самое для следующего кода (так как я не совсем уверен, какой из них будет правильным):

 memcpy(current_tuple->attributes[k].value, &v, 1);

Даже не уверен, что мне нужен здесь memcpy ...

Также я попытался выделить память, выполнив что-то вроде:

 current_tuple->attributes[k].value = (int *) malloc(sizeof(int));

только для получения "malloc: *** ошибка для объекта 0x100108e98: неверная контрольная сумма для освобожденного объекта - объект, вероятно, был изменен после освобождения."Насколько я понимаю, эта ошибка уже выделена для этого объекта, но я не вижу, где это произошло.Разве malloc (sizeof (attribute)) не выделяет только память, необходимую для хранения целого числа и двух указателей (т. Е. Не той памяти, на которую указывают указатели)?

Любая помощь будет принята с благодарностью!

С уважением, Василь

Ответы [ 3 ]

1 голос
/ 13 июня 2010
#include <stdio.h>
#include <string.h>
#include <stdlib.h>

#define STR_TYPE 1
#define INT_TYPE 2

typedef struct tagAttribute
{
    int type;
    char *name; 
    // anonymous union here
    union {
        char *value;
        int  ivalue;
    };
} attribute, *PATTRIBUTE;


typedef struct tagTuple
{
    int tuple_id;
    int attribute_count;
    attribute *attributes;
} tuple, *PTUPLE;


typedef struct tagTable
{
    char *name;
    int row_count;
    tuple *tuples;
} table, *PTABLE;

    // allocator for table 
PTABLE allocTable(char* name, int row_count) {
    PTABLE mytable = calloc(sizeof(table),1);
    mytable->row_count = row_count;
    mytable->name = strdup(name);
    mytable->tuples = (PTUPLE)calloc(row_count,sizeof(tuple));
    for(int i=0; i< row_count; i++) {
        mytable->tuples[i].tuple_id= i; // ?
    }
    return(mytable);
}

    // allocator for attributes
void allocAttributes( PTUPLE mytuple,  int attr_count) {
    mytuple->attributes =   (PATTRIBUTE) calloc(attr_count, sizeof(attribute));
    mytuple->attribute_count = attr_count;
}

void setAttributeStr(PATTRIBUTE pa, char *name, char *value) {
    pa->type = STR_TYPE;
    pa->name = strdup(name);
    pa->value = strdup(value);
}

void setAttributeInt(PATTRIBUTE pa, char *name, int value) {
    pa->type = INT_TYPE;
    pa->name = strdup(name);
    pa->ivalue = value;

}

int main (int argc, const char * argv[]) {
    // insert code here...
    printf("Test!\n");

        // allocate a table with two tuples
    PTABLE mytable = allocTable("my_table", 2);
        // allocate two attributes in the first tuple

    PTUPLE t0 = & mytable->tuples[0];
    PTUPLE t1 = & mytable->tuples[1];

    allocAttributes( t0, 2);
    allocAttributes( t1, 2);

    setAttributeStr(  &t0->attributes[0], "my_strng_field", "value0");
    setAttributeInt( &t0->attributes[1], "my_int_field", 0xBEEF);
        // now assign 
    setAttributeStr(  &t1->attributes[0], "my_second_strng_field", "value0");
    setAttributeInt( &t1->attributes[1], "my__second_int_field", 0xDEAD);


    return 0;
}
  • Вы должны быть осторожны с вашими выделениями
  • или использовать strdup () для строк, чтобы они позаботились об этом за вас

Работает на моемMAC.

Спасибо за поездку по переулку памяти (15 лет или около того)

1 голос
/ 14 июня 2010

Итак, у вас здесь происходит несколько вещей. Во-первых, не приводите возвращаемое значение malloc на языке программирования C. Далее это вызовет проблемы:

int v = atoi(value);
current_tuple->attributes[k].value = &v;

У вас есть значение указывает на память, выделенную в стеке. Это плохо, если вы получите к нему доступ после того, как текущая буква v вышла из области видимости.

Кроме того, вы не используете никакое условие ветвления, чтобы определить, должно ли значение быть строковым или целым. Таким образом, вы будете в конечном итоге с утечками памяти, при условии, что вы правильно назначили вещи, как упоминалось ранее. Я подозреваю, что это отчасти потому, что это всего лишь пример.

Проверьте возвращаемое значение malloc. Вы можете создать функцию-обертку, чтобы сделать это для вас. Кроме того, вы можете захотеть сделать лучшую запись.

По сути, вам нужно больше узнать о том, как работают указатели в C, и о разнице между размещением в куче и размещением в стеке. Стек или автоматические переменные выходят из области видимости. Когда вы malloc оно остается вечным, пока вы от него не избавитесь. Никогда не устанавливайте указатель, равный месту в памяти чего-то, выделенного в стеке, если вы действительно не хотите этого делать (опять же, ваш пример с «v», этот адрес памяти будет недействительным, как только эта конкретная итерация цикла) закончен, наихудший случай здесь, когда он тестируется, и вы не замечаете ошибку.

Кроме того, "//" не является комментарием в стиле ANSI-C89. Используйте "/ " и " /"

Я сделал пару изменений; Я не могу гарантировать, что это будет работать сейчас, поскольку я не проверял это очевидно. Тем не менее, я рекомендую прочитать C Язык программирования

char value[10]; /* assuming no value is longer than 10 chars */
int i, j, k;

table * data = malloc(sizeof(table));
     if(!data)
         exit(1); /* error */

data->name = "table";
data->row_count = number_of_lines;
data->tuples = malloc(number_of_lines*sizeof(tuple));
     if(!data->tuples)
         exit(1); /* error */

tuple* current_tuple;

for(i=0; i<number_of_lines; i++)
{
    current_tuple = &data->tuples[i];
    current_tuple->tuple_id = i;
    current_tuple->attribute_count = 16; /* static in our system */
    current_tuple->attributes = malloc(16*sizeof(attribute));

    for(k = 0; k < 16; k++)
    {
        current_tuple->attributes[k].name = attribute_names[k];

                        if(k % 2)
                        {
               /* for int values:*/
               current_tuple->attributes[k].type = DB_ATT_TYPE_INT;
               /* write data into value-field */
                               current_tuple->attributes[k].value = malloc(sizeof(int));
                               if(!current_tuple->attributes[k].value)
                               {
                                    exit(1); /* error */
                               }    
               *current_tuple->attributes[k].value = atoi(value);

                        }
                        else
                        {
               /* for string values: */
               current_tuple->attributes[k].type = DB_ATT_TYPE_STRING;
                               current_tuple->attributes[k].value = malloc(strlen(value) +1);
                               if(!current_tuple->attributes[k].value)
                               {
                                    exit(1); /* error */
                               }
               strcpy(current_tuple->attributes[k].value, value);
                        }
    }


}
1 голос
/ 13 июня 2010

То есть для строк вы сохраняете указатель на строку в поле значения attribute, но для целых чисел вы хотите поместить само число в поле значения? Тогда ты слишком стараешься. Просто используйте:

current_tuple->attributes[k].value = (void *)v;

Если вы хотите сохранить указатель на целое число, вам нужно выделить для него место, так как хранение указателя на переменную локальной области может закончиться слезами. Как то так:

int *v = malloc(sizeof(int));
*v = atoi(value);
current_tuple->attributes[k].value = v;

Аналогично для строк, вы всегда храните один и тот же указатель локальной переменной value в своих структурах данных. Вероятно, вам следует заняться копированием или выделением памяти, чтобы избежать постоянной перезаписи ваших данных.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...