更新:我解决了我的问题(向下滚动)。
我正在编写一个小型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
等值。
答案 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语言抽象分配这似乎很有吸引力......享受:)