在 C 中替换数组中的元素的最有效方法是什么

What is the most efficient way to replace an element in an array in C

我一直在慢慢开发一个库,它允许用户用 C 语言动态构建数组。在我编写的许多函数中,我开发了一个解决方案,用另一个值替换用户定义索引处的值,但我不确定这是一个非常有效的解决方案,如果有人可能有更好的方法,我想知道不需要创建几个中间数组来存储数据。

我正在使用标题为 Arraytypedef struct,它作为指针变量 array 的容器,以及包含活动长度的 len数组,size 包含数组的分配大小,elem 包含每个索引的内存分配,它可以根据用户选择的数据类型而改变,name 这是一个用户可以分配给每个数组实例化的字符串,以及 dat_type 引用 enum 来描述数组被实例化的数据类型。

到目前为止,我已经构建了几个与 Array 容器一起工作的函数,其中与这个问题最相关的是以下函数;

type_dat 包含 floatdoublecharint.

变量的枚举

Array 一个 struct 作为数组的容器。

array_mem_alloc 该函数为数组分配内存,不应直接调用。

init_array 此函数充当 array_mem_alloc 的包装器,是用户应如何实例化数组。这 returns 一个 Array 容器。

append_array 这允许用户将标量或数组附加到 Array 容器内的数组。

preappend_array 此函数允许用户将标量或数组添加到 Array 容器中数组的开头。

int_array_val 此函数从数组中检索整型变量。每种数据类型都有此函数的一个版本;但是,此特定功能与下面的示例相关。

replace_int_array_indice 此函数允许用户输入特定索引,并用另一个整数值替换该索引处的变量。我已经为这个功能编写了一个解决方案,但我不认为这是一个有效的实现。在下面的示例中,实现要求在 memmovememcpy 函数将所有数据汇集在一起​​之前创建两个中间数组来存储数据。 我希望有人能告诉我这个功能是否有比我在下面提供的更好的解决方案

我的文件如下所示

array.h

#ifndef ARRAY_H
#define ARRAY_H

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

typedef enum
{
    FLOAT,
    DOUBLE,
    CHAR,
    INT
} dat_type;
// --------------------------------------------------------------------------------

typedef struct
{
    void *array;  // Pointer to array
    size_t len;   // Active length of array
    size_t size;  // Number of allocated indizes
    int elem;     // Memory consumption per indice
    char name[20];   // The array name
    dat_type dat;
} Array;
// --------------------------------------------------------------------------------

void array_mem_alloc(Array *array, size_t num_indices);
// --------------------------------------------------------------------------------

Array init_array(dat_type dat, size_t num_indices, char *name);
// --------------------------------------------------------------------------------

int append_array(Array *array, void *elements, size_t count);
// --------------------------------------------------------------------------------

int int_array_val(Array *array, int indice);
// --------------------------------------------------------------------------------

int preappend_array(Array *array, void *elements, size_t count);
// --------------------------------------------------------------------------------

void replace_int_array_indice(Array *array, int index, int replacement_value);
#endif /* ARRAY_H */

Array.c

void array_mem_alloc(Array *array, size_t num_indices) {
    // Determine the total memory allocation and assign to pointer
    void *pointer;
    pointer = malloc(num_indices * array->elem);

    // If memory is full fail gracefully
    if (pointer == NULL) {
        printf("Unable to allocate memory, exiting.\n");
        free(pointer);
        exit(0);
    }
    // Allocate resources and instantiate Array
    else {
        array->array = pointer;
        array->len = 0;
        array->size = num_indices;
    }
}
// --------------------------------------------------------------------------------

Array init_array(dat_type dat, size_t num_indices, char *name) {
    // Determine memory blocks based on data type
    int size;
    switch(dat) {
        case FLOAT:
            size = sizeof(float);
            break;
        case INT:
            size = sizeof(int);
            break;
        case DOUBLE:
            size = sizeof(double);
            break;
        case CHAR:
            size = sizeof(char);
            break;
        default:
            printf("Data type not correctly entered, instantiating int array!\n");
            size = sizeof(int);
            dat = INT;
    }

    // Allocate indice size and call array_mem_alloc
    Array array;
    array.dat = dat;
    array.elem = size;
    array_mem_alloc(&array, num_indices);
    strcpy(array.name, name);
    return array;
}
// --------------------------------------------------------------------------------

int append_array(Array *array, void *elements, size_t count) {
    // Allocae more memory if necessary
    if (array->len + count > array->size) {
        size_t size = (array->len + count) * 2;
        void *pointer = realloc(array->array, size * array->elem);
        // If memory is full return operations
        if (pointer == NULL) {
            printf("Unable to allocate memory, exiting.\n");
            return 0;
        }
        // Allocate memory to variables and increment array size
        array->array = pointer;
        array->size = size;
    }
    // Append variables and increment the array length
    memcpy((char *)array->array + array->len * array->elem, elements, count * array->elem);
    array->len += count;
    return 1;
}

// --------------------------------------------------------------------------------

int preappend_array(Array *array, void *elements, size_t count) {
    // Allocae more memory if necessary
    if (array->len + count > array->size) {
        size_t size = (array->len + count) * 2;
        void *pointer = realloc(array->array, size * array->elem);
        // If memory is full return operations
        if (pointer == NULL) {
            printf("Unable to allocate memory, exiting.\n");
            exit(0);
        }
        // Allocate memory to variables and increment array size
        array->array = pointer;
        array->size = size;
    }
    // Preappend variables and increment the array length
    memmove(
    ((char *) array->array) + count * array->elem,
    array->array,
    array->len * array->elem);

    memcpy(array->array, elements, count * array->elem);
    array->len += count;
    return 1;
}

// --------------------------------------------------------------------------------

void replace_int_array_indice(Array *array, int index, int replacement_value) {

    // THIS FUNCTION WORKS, BUT I DO NOT THINK IT IS AN EFFICIENT IMPLEMENTATION
    // Copy data to intermediate array
    int arr[array->len];
    memcpy(arr, array->array, array->elem * array->len);
    memmove(((char *) array->array), arr + index + 1, array->len * array->elem);
    array->len -= index + 1;

    // preappend with replacement value
    preappend_array(array, &replacement_value, 1);

    // preappend with initial indices up to replaced index
    int new_arr[index - 1];
    memcpy(new_arr, arr, index * array-> elem);
    preappend_array(array, &new_arr, index);
}

main.c

#include "array.h"

int main(int argc, const char * argc[]) {
    size_t indices = 10;
    char name[6] = "array";
    dat_type dtype = INT;
    Array arr_test = init_array(dtype, indices, name);
    int a[6] = {1, 2, 3, 4, 5, 6};
    append_array(&arr_test, a, 6);
    replace_int_array_indice(&arr_test, 1, 5);
    for (int j = 0; j < array_test.len; j++) {
        printf("%d\n", int_array_val(&arr_test, j);
    }
}

你肯定想多了。

你只需要替换数组中的一个值,所以找到偏移量,正确转换,解引用并赋值:

* (int *) ((char *) array->array + index * array->elem) = replacement_value;

或者,在构建基本功能时继续使用 memcpy,并使用它来创建进一步的抽象。

void array_set(Array *array, size_t index, void *data) {
    memcpy(
        (char *) array->array + index * array->elem,
        data,
        array->elem);
}

void int_array_set(Array *array, size_t index, int value)
{
    array_set(array, index, &value);
}

可能要检查 index 是否有效。

顺便说一句,您的代码中存在内存损坏漏洞。在 init_array 中,当名称只有 20 个字节长时,您正在使用 strcpy(array.name, array);name 是用户控制的。您应该改用 strncpy(array.name, array, sizeof(array.name);