2012-08-02 1 views
1

이 질문은이 포인터 문제를 처리하는 모범 사례에 대한 것입니다.포인터 규칙 : 특정 요소에 대한 포인터 배열

필자는 csv를 읽는 함수에서 동적으로 생성 된 구조체 배열을 가지고 있습니다.

int init_from_csv(instance **instances,char *path) { 
    ... open file, get line count 
    *instances = (instance*) malloc((size_t) sizeof(instance) * line_count); 
    ... parse and set values of all instances 
    return count_of_valid_instances_read; 
} 
// in main() 
instance *instances; 
int ins_len = init_from_csv(&instances, "some/path/file.csv"); 

지금, 나는이 원시 데이터에 기능을 수행을 분할하고, 분할에 다시 같은 기능을 수행 할 수 있습니다. 이 데이터 세트는 상당히 클 수 있으므로 인스턴스를 복제하고 싶지 않습니다. 분할 된 구조체에 대한 포인터 배열을 원합니다.

instance **split = (instance**) malloc (sizeof(instance*) * split_len_max); 
int split_function(instance *instances, ins_len, instances **split){ 
    int i, c; 
    c = 0; 
    for (i = 0; i < ins_len; i++) { 
    if (some_criteria_is_true) { 
     split[c++] = &instances[i]; 
    } 
    return c; 
} 

지금 내 질문은 무엇을 가장 좋은 방법이나 구조체의 배열과 포인터의 배열 모두에서 기능을 수행하는 가장 읽을 수있는 방법이 될 것입니다? 간단한 예를 들면 count_data().

int count_data (intances **ins, ins_len, float crit) { 
    int i,c; 
    c = 0; 
    for (i = 0; i < ins_len; i++) { 
    if ins[i]->data > crit) { 
     ++c; 
    } 
    } 
    return c; 
} 

// code smell-o-vision going off by now 
int c1 = count_data (split, ins_len, 0.05); // works 
int c2 = count_data (&instances, ins_len, 0.05); // obviously seg faults 

내 init_from_csv의 malloc에 ​​인스턴스에 대한 포인터의 배열을 확인한 다음 인스턴스 내 배열을 malloc을 할 수있다. 나는 일련의 코드를 변경하기 전에 노련한 c 프로그래머가 이런 종류의 문제를 처리하는 방법을 배우고 싶다.

+0

당신은 그렇게 할 수 없습니다. 한 인스턴스에서 포인터의 배열을 전달하고 다른 인스턴스에서는 실제 구조체의 배열을 전달합니다. 즉 인덱싱이 사례 중 하나에서 엉망이 될 것입니다. 개별 항목에 대해 연산을 수행하는 함수와 배열의 각 유형을 처리하는 2 개의 도우미 함수가 3 가지 기능을 갖는 것이 좋습니다. – tbert

답변

2

다소 복잡해 보일지 모르지만 실제로 ** 포인터를 전달하여 기본 데이터 세트와 분할 모두에 대해 작업하려면 포인터에 대한 포인터를 만들어야합니다. 주요 데이터 세트. 여기 당신이 그것을 할 수있는 한 가지 방법 ...

size_t i, mem_reqd; 
instance **list_seg, *data_seg; 

/* Allocate list and data segments in one large block */ 
mem_reqd = (sizeof(instance*) + sizeof(instance)) * line_count; 
list_seg = (instance**) malloc(mem_reqd); 
data_seg = (instance*) &list_seg[line_count]; 

/* Index into the data segment */ 
for(i = 0; i < line_count; i++) { 
    list_seg[i] = &data_seg[i]; 
} 

*instances = list_seg; 

지금 당신은 항상 당신의 주요 목록 또는 분할 여부, instance* 포인터의 배열에서 작동 할 수는 있습니다. 여분의 메모리를 사용하고 싶지는 않지만, instance 구조체가 아주 작지 않은 경우 각 인스턴스에 여분의 포인터를 할당하면 혼동을 막아 코드 중복을 방지하는 것이 좋습니다.

당신이 당신의 주요 인스턴스 목록을 완료하면, 당신은이 작업을 수행 할 수 있습니다, 당신이 할 수있는

struct instance_list { 
    instance ** data; 
    size_t length; 
    int owner; 
}; 

그 방법 :

void free_instances(instance** instances) 
{ 
    free(instances); 
} 

내가 구조체로이를 구현하도록 유혹 할 것 더 좋은 방법으로 함수에서 반환이 :

이제
instance_list* alloc_list(size_t length, int owner) 
{ 
    size_t i, mem_reqd; 
    instance_list *list; 
    instance *data_seg; 

    /* Allocate list and data segments in one large block */ 
    mem_reqd = sizeof(instance_list) + sizeof(instance*) * length; 
    if(owner) mem_reqd += sizeof(instance) * length; 
    list = (instance_list*) malloc(mem_reqd); 
    list->data = (instance**) &list[1]; 
    list->length = length; 
    list->owner = owner; 

    /* Index the list */ 
    if(owner) { 
     data_seg = (instance*) &list->data[line_count]; 
     for(i = 0; i < line_count; i++) { 
      list->data[i] = &data_seg[i]; 
     } 
    } 

    return list; 
} 

void free_list(instance_list * list) 
{ 
    free(list); 
} 

void erase_list(instance_list * list) 
{ 
    if(list->owner) return; 
    memset((void*)list->data, 0, sizeof(instance*) * list->length); 
} 

, CSV에서로드 함수는 FOC 필요가 없습니다 이 괴물을 만드는 것에 대한 세부 사항을 우리에게 알려주기 때문에 단순히해야 할 일을 할 수 있습니다. 이제 데이터가 포함되어 있거나 단순히 다른 목록을 가리키고 있는지 여부와 관계없이 다른 함수의 목록을 반환 할 수 있습니다.

instance_list* load_from_csv(char *path) 
{ 
    /* get line count... */ 
    instance_list *list = alloc_list(line_count, 1); 
    /* parse csv ... */ 
    return list; 
} 

등 ... 글쎄, 당신은 아이디어를 얻습니다. 이 코드가 컴파일되거나 작동한다는 보장은 없지만 가까이 있어야합니다. 중요한 것은 배열을 사용하여 무언가를 할 때마다 단순한 배열보다 약간 더 복잡해지기 때문에 캡슐화하기위한 그 작은 노력을하는 것이 유용하다는 것입니다. 이는 분석 등을 위해 사용할 주요 데이터 구조이므로 자체 데이터 유형이 있다는 점에서 조금만 더 자세하게 설명하는 것이 좋습니다.

나는 과용 이었습니까?=)

+0

매우 철저한 답변을 해주셔서 감사합니다! – Nate