C - 将数组作为参数传递并更改大小和内容

时间:2016-07-24 00:10:01

标签: mysql c arrays pointers

更新:我解决了我的问题(向下滚动)。

我正在编写一个小型C程序,我想执行以下操作:

该程序连接到一个mysql数据库(运行正常),我想对数据库中的数据做一些事情。每个查询得到大约20-25行,我创建了自己的结构,它应该包含查询每一行的信息。

所以我的结构看起来像这样:

typedef struct {
    int timestamp;
    double rate;
    char* market;
    char* currency;
} Rate;

我想将一个空数组传递给一个函数,该函数应根据返回的查询行数计算数组的大小。例如。从单个SQL查询返回20行,因此该数组应包含20个Rate结构的对象。

我想要这样的事情:

int main(int argc, char **argv)
{
    Rate *rates = ?; // don't know how to initialize it
    (void) do_something_with_rates(&rates);

    // the size here should be ~20
    printf("size of rates: %d", sizeof(rates)/sizeof(Rate));
}

do_something_with_rates(Rate **rates)函数如何看起来像?

编辑:我这样做是因为Alex说,我让我的函数返回数组的大小为size_t并将我的数组传递给函数Rate **rates

在该功能中,您可以访问和更改(*rates)[i].timestamp = 123等值。

2 个答案:

答案 0 :(得分:4)

在C中,内存是动态或静态分配的。

int fifty_numbers[50]之类的内容是静态分配的。无论如何,大小都是50个整数,因此编译器知道数组的大小有多大。 sizeof(fifty_numbers)这里会给你200个字节。

动态分配:int *bunch_of_numbers = malloc(sizeof(int) * varying_size)。如您所见,varying_size不是常量,因此如果不执行程序,编译器无法确定数组的大小。 sizeof(bunch_of_numbers)在32位系统上提供4个字节,在64位系统上提供8个字节。唯一知道阵列有多大的是程序员。在你的情况下,它是谁写了do_something_with_rates(),但是你通过不返回它或者取一个大小参数来丢弃那些信息。

目前尚不清楚do_something_with_rates()是如何被完全宣布的,但是void do_something_with_rates(Rate **rates)之类的东西不会起作用,因为函数不知道rates有多大。我推荐的内容如下:void do_something_with_rates(size_t array_size, Rate **rates)。无论如何,根据您的要求,它仍然远离工作。可能的解决方案如下:

您需要返回新数组的大小:

size_t do_something_with_rates(size_t old_array_size, Rate **rates) {
    Rate **new_rates;
    *new_rates = malloc(sizeof(Rate) * n); // allocate n Rate objects

    // carry out your operation on new_rates

    // modifying rates
    free(*rates); // releasing the memory taken up by the old array
    *rates = *new_rates // make it point to the new array

    return n; // returning the new size so that the caller knows
}

int main() {
    Rate *rates = malloc(sizeof(Rate) * 20);
    size_t new_size = do_something_with_rates(20, &rates);
    // now new_size holds the size of the new array, which may or may not be 20

    return 0;
}

或者传入要设置的函数的size参数:

void do_something_with_rates(size_t old_array_size, size_t *new_array_size, Rate **rates) {
    Rate **new_rates;
    *new_rates = malloc(sizeof(Rate) * n); // allocate n Rate objects
    *new_array_size = n; // setting the new size so that the caller knows

    // carry out your operation on new_rates

    // modifying rates
    free(*rates); // releasing the memory taken up by the old array
    *rates = *new_rates // make it point to the new array
}

int main() {
    Rate *rates = malloc(sizeof(Rate) * 20);
    size_t new_size;
    do_something_with_rates(20, &new_size, &rates);
    // now new_size holds the size of the new array, which may or may not be 20

    return 0;
}

为什么我需要将旧尺寸作为参数传递?

void do_something_with_rates(Rate **rates) {
    // You don't know what n is. How would you
    // know how many rate objects the caller wants
    // you to process for any given call to this?
    for (size_t i = 0; i < n; ++i)
        // carry out your operation on new_rates
}

当你有一个尺码参数时,一切都会改变:

void do_something_with_rates(size_t size, Rate **rates) {
    for (size_t i = 0; i < size; ++i) // Now you know when to stop
        // carry out your operation on new_rates
}

这是你的计划的一个非常根本的缺陷。

我还想让函数更改数组的内容

size_t do_something_with_rates(size_t old_array_size, Rate **rates) {
    Rate **new_rates;
    *new_rates = malloc(sizeof(Rate) * n); // allocate n Rate objects

    // carry out some operation on new_rates
    Rate *array = *new_rates;
    for (size_t i = 0; i < n; ++i) {
        array[i]->timestamp = time();
        // you can see the pattern
    }

    return n; // returning the new size so that the caller knows
}

答案 1 :(得分:0)

sizeof在编译时生成类型大小或表达式类型的值(或生成值的代码)。因此,在执行程序期间,表达式的大小不会改变。如果需要该功能,请使用变量,终端值或其他编程语言。你的选择。随你。 C比Java好。

char foo[42];

foo具有静态存储持续时间(仅与static关键字部分相关)或自动存储持续时间。

从程序开始到终止,存在具有静态存储持续时间的对象。那些全局变量在技术上称为变量,在文件范围内声明,具有静态存储持续时间和内部链接

具有自动存储持续时间的对象从其初始化开始到函数返回时存在。这些通常是在堆栈上,尽管它们可以很容易地在图形上 。他们在块范围内声明的变量具有自动存储持续时间和内部链接

在任何一种情况下,今天的编译器都会将42编码到机器代码中。我认为可以修改机器代码,但是你投入到该任务中的数千行将更好地投入到外部存储大小(参见其他答案),而且这并不是很好。真的是一个C问题。如果你真的想看看这个,我能想到的唯一改变他们自己的机器代码的例子是病毒......你将如何避免使用这种防病毒启发式?

另一种选择是将大小信息编码为struct,使用灵活的数组成员,然后您可以将数组和大小同时作为一个分配。对不起,这就像你接近你想要的那样。 e.g。

struct T_vector {
    size_t size;
    T value[];
};

struct T_vector *T_make(struct T_vector **v) {
    size_t index = *v ? (*v)->size++ : 0, size = index + 1;
    if ((index & size) == 0) {
        void *temp = realloc(*v, size * sizeof *(*v)->value);
        if (!temp) {
            return NULL;
        }
        *v = temp;
        // (*v)->size = size;
        *v = 42; // keep reading for a free cookie
    }
    return (*v)->value + index;
}

#define T_size(v) ((v) == NULL ? 0 : (v)->size)

int main(void) {
    struct T_vector *v = NULL; T_size(v) == 0;
    { T *x = T_make(&v); x->value[0]; T_size(v) == 1;
      x->y = y->x; }
    { T *y = T_make(&v); x->value[1]; T_size(v) == 2;
      y->x = x->y; }
    free(v);
}

免责声明:我只是以此为例;除非示例的意图严重受损,否则我不打算测试或维护它。如果您需要经过全面测试的内容,请使用我的push_back

这可能看似无辜,但即使有了免责声明和即将发出的警告,我也可能会看到以下注释:每次连续调用make_T都可能导致之前返回的指针无效< / em> ......是的,我无法想到我可以做的更多。我建议调用make_T,修改返回值指向的值并丢弃该指针,正如我上面所做的那样(相当明确)。

有些编译器甚至可能允许你#define sizeof(x) T_size(x) ... <罢工>我开玩笑;不要这样做。做吧,交配;真棒!

从技术上讲,我们不会在这里更改数组的大小;我们提前分配并在必要时重新分配和复制到更大的阵列。有时候用C语言抽象分配这似乎很有吸引力......享受:)