2010-06-13 3 views
2

저는 최근 C에서 저의 석사 학위 논문을 작성하기 시작했습니다. 오랫동안 사용하지 않았습니다. Java에 익숙해지면서, 나는 항상 모든 종류의 문제에 직면하고 있습니다. 나는 지난 2 일 동안 누군가와 고투하고 있었기 때문에 누군가 다음 날을 도울 수 있기를 바랍니다.메모리 할당 및 값 할당에 관한 기본 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'); 

데이터를로드하고 구문 분석하고 할당 할 수도 있습니다. 그러나 모든 값은 동일한 메모리 위치를 가리 키므로 데이터를로드 한 후에 모든 행이 동일하게 보이므로 할당 비트가 버그가 있습니다. 다음은 내가하는 일입니다.

나는 이것이 완벽하게 인식하지 못하고 왜 작동하지 않는지, 나는 어떻게 작동시키는 지 알 수 없습니다. 다음 중 어떤 것도 작동하지 않았습니다. 어떤 작업도 수행하지 않았습니다.

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

이 경우 액세스 오류가 발생합니다.

또한 내가했습니다 ... 방어 적이기 내가 여기 필요한 경우

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

도 확실하지 : (나는 하나의 올바른 사용을 될 것이라고 확신 아니에요 이후) 다음 코드를 동일 같은 것을 수행하여 메모리를 할당 시도 : "개체 0x100108e98는 *** 오류 : malloc에를 잘못된 체크섬을 해제 개체에 대해 - 객체가 아마 해제 후 수정되었습니다."

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

만 얻을 수 있습니다 이 오류를 이해하는 한,이 개체에 이미 메모리가 할당되어 있지만이 문제가 발생한 곳을 알 수 없습니다. malloc (sizeof (attribute))은 정수와 두 개의 포인터 (즉, 포인터가 가리키는 메모리가 아닌)를 저장하는 데 필요한 메모리 만 할당합니까?

도움이 될 것입니다.

안부, 바실 당신 attribute의 value 필드의 문자열에 대한 포인터를 저장하고 문자열 그래서

답변

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


} 
,617을 읽어 보시기 바랍니다.
+0

많은 분들께도 감사드립니다! 다른 유형에 대해서 - 나는 분기를 했으므로 여기에있는 예제에는 포함하지 않았다. 그리고 당신은 아마 맞을 것입니다. C에 대한 내 학부생의 지식은 부족한 것 같습니다. 나는 도서관에 들러서 당신이 추천 한 책을 찾아야합니다. – VHristov

1

,하지만 당신은 값 필드에 정수 자체를 데려 가고 싶다는 정수 하시나요? 그럼 너는 너무 열심히 노력하고있어. 그냥 사용

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()를 사용합니다. 메모리 레인 다운 여행을위한

감사합니다 (그래서 십오년 또는)

+0

직업에 대한 명성. 나는 그것을 실제로 보지 않았다. strdup()은 표준이 아니지만 그 기능을 재현하기 쉽습니다. :) – BobbyShaftoe

+0

노력해 주셔서 대단히 감사합니다! 내가 정확히 무슨 일이 일어 났는지 이해할 수있게 된 후에 그것을 시험해 볼 것입니다! :) – VHristov

+0

나는 calloc의 "올바른"사용법이 calloc (size_t number_of_elements, size_t element_size)이며 다른 방법으로 작성한 것이 아니라는 것을 눈치 챘다. 지금까지 두 가지가 모두 효과적 이었지만 (아마도 두 값을 곱한 값이기 때문에) 먼저 여러 요소가 있어야합니다. 누군가가 실수 할 경우를 대비해 코드를 변경하고 싶을 수도 있습니다.) – VHristov