转换 void* 指针

问题描述 投票:0回答:1
当我尝试在 C 语言的通用排序库中使用 compelx 结构时,我的代码出现问题:

我有一个二进制合并插入排序,它接受一个 void 指针(数组的第一个元素),并且,可以处理 int 和 string 数组(所有统一测试都通过)。

现在我尝试将它与以下数组一起使用:

struct record{ int id; char* string_field_1; int integer_field_2; double float_field_3; };
我必须根据所选字段进行订购。
这是从 csv 文件获取数据的示例

订购方式由

选择

switch (field) { case 1://struct_array_get(array,0) return the first element of the array merge_binary_insertion_sort(struct_array_get(array,0), struct_array_size(array), sizeof(struct record), k, precedes_record_string_field);
数组已正确加载,因为打印功能

for(unsigned long i=0;i<el_num;i++){ array_element = (struct record *)struct_array_get(array, i); printf("<POSIZION:%d, ID:%d, String:%s, Integer:%d, Float:%lf >\n",i,array_element->id,array_element->string_field_1,array_element->integer_field_2,array_element->float_field_3); }
可以显示数组中的所有记录。

所以当调用排序函数时出现问题:

void merge_binary_insertion_sort(void *base, size_t nitems, size_t size, size_t k, CompareFunction compare){ if(base == NULL){ fprintf(stderr,"the given array cannot be null"); exit(EXIT_FAILURE); } else merge_binary_insertion_sort_rec(base, 0, nitems-1, k, size, compare); } void merge_binary_insertion_sort_rec(void *arr, int left, int right, size_t k, size_t elementSize, CompareFunction compare) { if (left < right) { if (right - left + 1 <= k) { // Use bin_insertion_sort for small subarrays bin_insertion_sort(arr + (left * elementSize), right - left + 1, elementSize, compare); } else { int mid = left + (right - left) / 2; // Sort the left and right halves recursively merge_binary_insertion_sort_rec(arr, left, mid, k, elementSize, compare); merge_binary_insertion_sort_rec(arr, mid + 1, right, k, elementSize, compare); // Merge the sorted halves merge(arr, left, mid, right, elementSize, compare); } } } int binary_search(void *arr, void *item, int low, int high, CompareFunction compare, size_t elementSize) { if (high <= low){ return (compare(item, arr + low * elementSize) > 0) ? (low + 1) : low ; } int mid = (low + high) / 2; int cmpResult = compare(item, arr + mid * elementSize); if (cmpResult == 0) return mid + 1; if (cmpResult > 0) return binary_search(arr, item, mid + 1, high, compare, elementSize); return binary_search(arr, item, low, mid - 1, compare, elementSize); } void bin_insertion_sort(void *arr, int n, size_t elementSize, CompareFunction compare) { int i, loc, j; void *selected = malloc(elementSize); if (selected == NULL) { fprintf(stderr, "Errore nell'allocazione di memoria per 'selected'\n"); exit(EXIT_FAILURE); } for (i = 1; i < n; ++i) { j = i - 1; memcpy(selected, arr + i * elementSize, elementSize); // Find location where selected should be inserted loc = binary_search(arr, selected, 0, j, compare, elementSize); // Move all elements after location to create space while (j >= loc) { memcpy(arr + (j + 1) * elementSize, arr + j * elementSize, elementSize); j--; } memcpy(arr + (j + 1) * elementSize, selected, elementSize); } free(selected); } void merge(void *arr, int left, int mid, int right, size_t elementSize, CompareFunction compare) { int i, j, k; int n1 = mid - left + 1; int n2 = right - mid; // Create temporary arrays for the left and right subarrays void *L = malloc(n1 * elementSize); void *R = malloc(n2 * elementSize); // Copy data from the original array to the temporary arrays memcpy(L, arr + (left * elementSize), n1 * elementSize); memcpy(R, arr + ((mid + 1) * elementSize), n2 * elementSize); // Merge the temporary arrays back into the original array i = 0; // Initial index of left subarray j = 0; // Initial index of right subarray k = left; // Initial index of merged subarray while (i < n1 && j < n2) { void *leftElem = L + (i * elementSize); void *rightElem = R + (j * elementSize); if (compare(leftElem, rightElem) <= 0) { // If left element <= right element, copy the left element to the merged subarray memcpy(arr + (k * elementSize), leftElem, elementSize); i++; } else { // If left element > right element, copy the right element to the merged subarray memcpy(arr + (k * elementSize), rightElem, elementSize); j++; } k++; } // Copy any remaining elements from the left subarray while (i < n1) { memcpy(arr + (k * elementSize), L + (i * elementSize), elementSize); i++; k++; } // Copy any remaining elements from the right subarray while (j < n2) { memcpy(arr + (k * elementSize), R + (j * elementSize), elementSize); j++; k++; } // Free the temporary arrays free(L); free(R); }
我们只能关注binary_search,问题是:
当我调用 

return (compare(item, arr + low * elementSize) > 0) 时? (低+1):低; 对于记录数组,使用此比较函数

static int precedes_record_string_field(const void* r1_p, const void* r2_p) { if (r1_p == NULL || r2_p == NULL) { fprintf(stderr, "precedes_record_string_field: one of the parameters is a null pointer\n"); exit(EXIT_FAILURE); } const struct record* rec1_p = (const struct record*)r1_p; const struct record* rec2_p = (const struct record*)r2_p; printf("Record 1: ID=%d, String=%s, Integer=%d, Float=%f\n", rec1_p->id, rec1_p->string_field_1, rec1_p->integer_field_2, rec1_p->float_field_3); sleep(1); printf("Record 2: ID=%d, String=%s, Integer=%d, Float=%f\n", rec2_p->id, rec2_p->string_field_1, rec2_p->integer_field_2, rec2_p->float_field_3); sleep(5); return strcmp(rec1_p->string_field_1, rec2_p->string_field_1); }
它打印rec2数据,但不打印rec1数据,所以我认为它可以转换arr + low * elementSize指针,但不能转换void * item指针。

我在内存地址管理中做错了什么?

我陷入困境,因为我对数组中的单个、空和多个字符串和 int 进行的所有统一测试都工作正常。

谢谢大家。

c algorithm sorting casting void-pointers
1个回答
0
投票
你写的方式看起来非常非常非常复杂。

Maybe you could test the functions first... I will show you a methodical way of writing his, using your `struct` and `qsort`, that you can easily adapt...
将物品分开

typedef struct { int id; char* string; int i_field; double d_field; } Target; int cmp_1(const void*, const void*); int cmp_2(const void*, const void*); int cmp_3(const void*, const void*); int cmp_4(const void*, const void*); int so_show(unsigned, Target[], const char*);
这里有您的数据记录、4 个必需的函数和一个显示结果的函数

使用

封装并围绕数据编写代码。

看这个:

Target some_value[] = { [0] = {.id = 42, .string = "value 33", .i_field = 4242, .d_field = 42.42}, [1] = {.id = 4, .string = "stack", .i_field = 42, .d_field = 42.242}, [2] = {.id = 342, .string = "overflow", .i_field = 4, .d_field = 142.42}, [3] = {.id = 412, .string = "take the survey", .i_field = 2, .d_field = 2142.42}, };
这是测试你所有功能的数据。

###'

main

 测试###

这里:

    数组按照声明的方式打印
  • 数组按每个条件排序并显示
so_show(4, some_value, "\nBefore sort:\t"); qsort(some_value, 4, sizeof(Target), cmp_1); so_show(4, some_value, "\nAfter sort by id:\t"); qsort(some_value, 4, sizeof(Target), cmp_2); so_show( 4, some_value, "\nAfter sort by string field:\t"); qsort(some_value, 4, sizeof(Target), cmp_3); so_show( 4, some_value, "\nAfter sort by integer field:\t"); qsort(some_value, 4, sizeof(Target), cmp_4); so_show( 4, some_value, "\nAfter sort by integer field:\t");
输出

Before sort: 4 records |=========================================================| | id | string value | integer | double | |=========================================================| | 42 | " value 33" | 4242 | 42.4200 | | 4 | " stack" | 42 | 42.2420 | | 342 | " overflow" | 4 | 142.4200 | | 412 | " take the survey" | 2 | 2142.4200 | |=========================================================| After sort by id: 4 records |=========================================================| | id | string value | integer | double | |=========================================================| | 4 | " stack" | 42 | 42.2420 | | 42 | " value 33" | 4242 | 42.4200 | | 342 | " overflow" | 4 | 142.4200 | | 412 | " take the survey" | 2 | 2142.4200 | |=========================================================| After sort by string field: 4 records |=========================================================| | id | string value | integer | double | |=========================================================| | 342 | " overflow" | 4 | 142.4200 | | 4 | " stack" | 42 | 42.2420 | | 412 | " take the survey" | 2 | 2142.4200 | | 42 | " value 33" | 4242 | 42.4200 | |=========================================================| After sort by integer field: 4 records |=========================================================| | id | string value | integer | double | |=========================================================| | 412 | " take the survey" | 2 | 2142.4200 | | 342 | " overflow" | 4 | 142.4200 | | 4 | " stack" | 42 | 42.2420 | | 42 | " value 33" | 4242 | 42.4200 | |=========================================================| After sort by integer field: 4 records |=========================================================| | id | string value | integer | double | |=========================================================| | 4 | " stack" | 42 | 42.2420 | | 42 | " value 33" | 4242 | 42.4200 | | 342 | " overflow" | 4 | 142.4200 | | 412 | " take the survey" | 2 | 2142.4200 | |=========================================================|
而且好像还可以。

这样更简单:首先测试所有功能。

既然您说代码已经适用于整数,那么只需确保排序代码真正抽象了数据记录即可。 一般来说,这只是编写正确的交换函数的情况。并特别注意导航过程...

完整

C
代码

#include <stdio.h> #include <stdlib.h> #include <string.h> typedef struct { int id; char* string; int i_field; double d_field; } Target; int cmp_1(const void*, const void*); int cmp_2(const void*, const void*); int cmp_3(const void*, const void*); int cmp_4(const void*, const void*); int so_show(unsigned, Target[], const char*); int main(void) { Target some_value[] = { [0] = {.id = 42, .string = "value 33", .i_field = 4242, .d_field = 42.42}, [1] = {.id = 4, .string = "stack", .i_field = 42, .d_field = 42.242}, [2] = {.id = 342, .string = "overflow", .i_field = 4, .d_field = 142.42}, [3] = {.id = 412, .string = "take the survey", .i_field = 2, .d_field = 2142.42}, }; so_show(4, some_value, "\nBefore sort:\t"); qsort(some_value, 4, sizeof(Target), cmp_1); so_show(4, some_value, "\nAfter sort by id:\t"); qsort(some_value, 4, sizeof(Target), cmp_2); so_show( 4, some_value, "\nAfter sort by string field:\t"); qsort(some_value, 4, sizeof(Target), cmp_3); so_show( 4, some_value, "\nAfter sort by integer field:\t"); qsort(some_value, 4, sizeof(Target), cmp_4); so_show( 4, some_value, "\nAfter sort by integer field:\t"); }; // main int cmp_1(void* one, void* other) { Target* a = one; Target* b = other; if (a->id < b->id) return -1; if (a->id == b->id) return 0; return 1; }; int cmp_2(void* one, void* other) { // now for the string Target* a = one; Target* b = other; return strcmp(a->string, b->string); }; int cmp_3(void* one, void* other) { Target* a = one; Target* b = other; if (a->i_field < b->i_field) return -1; if (a->i_field == b->i_field) return 0; return 1; }; int cmp_4(void* one, void* other) { Target* a = one; Target* b = other; if (a->d_field < b->d_field) return -1; if (a->d_field == b->d_field) return 0; return 1; }; int so_show(unsigned N, Target r[], const char* msg) { if (r == NULL) return -1; if (msg != NULL) printf("%s", msg); printf("%d records\n", N); const char* l0 = "\ | id | string value | integer | double |"; const char* l1 = "\ |=========================================================|"; printf("%s\n%s\n%s\n", l1,l0,l1); for ( unsigned u=0;u<N;u+=1) printf( "| %4d | \"%20s\" | %8d | %12.4f |\n", r[u].id, r[u].string, r[u].i_field, r[u].d_field); printf("%s\n\n",l1); return 0; }
    
© www.soinside.com 2019 - 2024. All rights reserved.