2010-06-13 35 views
2

我最近開始在C中使用我的碩士論文,我很久沒有使用它了。習慣了Java,我現在總是面臨着各種各樣的問題。我希望有人能夠幫助我,因爲過去兩天我一直在努力。關於內存分配和賦值的基本C問題

所以我有一個非常基本的數據庫模型:表,元組,屬性,我試圖加載一些數據到這個結構中。以下是定義:

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(屬性))是否只分配存儲一個整數和兩個指針所需的內存(即不是這些指針指向的內存)?

任何幫助將不勝感激!

問候, Vassil

回答

1

所以,你有幾件事情會在這裏。首先,不要在C編程語言中投入返回值malloc。接下來,這將引起麻煩:

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

您正在爲在堆棧上分配的內存賦值。如果在當前「v」超出範圍之後訪問它,那很糟糕。

此外,您沒有使用任何分支條件來確定值應該是字符串還是int。因此,假設您正如前面提到的那樣正確地分配了內容,那麼最終會發生內存泄漏。我懷疑這部分是因爲它只是一個例子。

檢查返回值malloc。你可以創建一個包裝函數來爲你做這件事。另外,你可能想要做一些更好的日誌記錄。

本質上,您需要更熟悉指針如何在C中工作以及在堆上分配和在堆棧上分配之間的區別。堆棧或自動變量超出範圍。當你malloc它保持永遠,直到你擺脫它。除非你確實要這麼做,否則不要設置一個等於堆棧中分配的內存位置的指針(再次,你用「v」作爲例子,該內存地址將在該循環的特定迭代中立即失效完成後,最糟糕的情況是它在測試時會起作用,並且您沒有注意到該錯誤。

此外,「//」不是ANSI-C89樣式的註釋。使用「/ 」和「 /」

我做了一些改動,我不能保證這將現在的工作,因爲我還沒有明顯地測試它。然而,我建議你閱讀C Programming Language

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


} 
+0

非常感謝你!關於不同的類型 - 我有分支,我只是沒有在這裏的例子中包含它。你可能是對的,我的C本科知識似乎不夠充分,我應該去圖書館看看你推薦的書。 – VHristov 2010-06-13 21:21:26

1

因此,對於字符串你保存一個指向一個attribute的值字段中的字符串,而是要放在值字段的整數本身整數?那你就太努力了。只需使用:

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

如果你想一個指針保存到整數,你將需要爲它分配空間,因爲存儲一個指向本地作用域的變量將會在眼淚中結束。事情是這樣的:

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

同樣的字符串,你總是存儲在同一個本地變量的指針value到你的數據結構。你應該做一些複製或內存分配,以防止不斷覆蓋你的數據。

1
#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; 
} 
  • 你需要注意你的分配
  • 或讓他們照顧這對你

作品在我的Mac使用的字符串的strdup()。

感謝一趟下來記憶裏(15歲左右)

+0

工作的榮譽。我沒有真正看過它。我只會說strdup()不是標準的,但它的功能很容易重現。 :) – BobbyShaftoe 2010-06-13 20:49:09

+0

非常感謝您的努力!在我設法瞭解究竟發生了什麼之後,會試試看! :) – VHristov 2010-06-13 21:13:08

+0

我只是注意到,calloc的「正確」用法是calloc(size_t number_of_elements,size_t element_size),而不是寫下來的其他方式。兩者都爲我工作到目前爲止(因爲它可能只是乘以這兩個值),但它應該是第一個元素的數量。也許你想改變你的代碼,以防有人絆倒它;) – VHristov 2010-08-04 14:53:42