一、问题来源
之前有看到C/C++中的柔型数组(又叫变长数组)(又叫0长数组),据说好处多得很,但一直没有机会用到,今天突发奇想用这个柔性数组重写之前的一些代码(毕竟之前的想法:不好用定长数组的场合只能用链表模拟实现)。
二、问题描述
使用柔性数组后,发现出现了很多问题,接下来我就好好描述一下我遇到的问题,其中删除了部分没有用到的代码:
问题:循环出错。插入出错。查询出错
代码:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
typedef struct {
int length; //总长度
int cursor; //下一个要插入元素的位置
int data[0];
}order_table;
order_table create_order_table(int length); //创建一个柔性数组
void insert_order_table_element(order_table *table, int element); //向柔性数组里添加元素
void binary_search(order_table table, int element); //查找有序表中的元素
int main(void)
{
int table_length;
int table_index;
int element;
printf("Please enter the length of the ordered table:\n");
scanf("%d", &table_length);
order_table table = create_order_table(table_length);
printf("Please enter the elements of the ordered table:\n");
for (table_index = 0; table_index < table_length; table_index++)
{
printf("table's total length is %d, now insert index is %d\n", table_length, table_index);
scanf("%d", &element);
insert_order_table_element(&table, element);
}
for(table_index=0;table_index<table.length;)
{
printf("search index:%d, address:%p\n", table_index, &(table.data[table_index]));
printf("%d\n", table.data[table_index]);
table_index += 1;
}
printf("Please enter the element which you want to search:\n");
scanf("%d", &element);
binary_search(table, element);
}
order_table create_order_table(int length)
{
order_table* table = (order_table*)malloc(sizeof(order_table) + sizeof(int)*length);
table->length = length;
table->cursor = 0;
return *table;
}
void insert_order_table_element(order_table *table, int element)
{
printf("\ninsert before:%d, address:%p\n", table->cursor, &(table->data[table->cursor]));
table->data[table->cursor] = element;
printf("insert element:%d\n", element);
(table->cursor)++;
printf("insert after:%d\n", table->cursor);
}
void binary_search(order_table table, int element)
{
int temp_index;
int low = 0, high = table.length, middle;
int key;
while (low <= high)
{
middle = (low + high) / 2;
key = table.data[middle];
printf("binary_index:%d, key:%d\n", middle, key);
if (key == element)
{
printf("Search successful, it's in %d element\n", middle);
return;
}
else if (table.data[middle] < element)
low = middle + 1;
else
high = middle - 1;
}
printf("Search failed\n");
}
结果1:????恕我书读的少,想不明白这个错误,插入时的地址和查询是的地址一样,但是值怎么不对。。而且为啥是1,2,3,5,5。。不应该是1,2,3,4,5吗?
结果2: ennnn,好像哪里不对,输入了5个值后为什么没有跳出来,还能继续输入。。。
结果3: 忽然间我想到了一点,会不会是redhat7的原因呢?不支持柔型数组?于是我换了centos8来测试,但是????????????说好的循环5次呢?而且也没有插进去值呀。
。。。。。。。。。。。。。总之遇到了很多莫名其妙问题,有一些因为我解决问题尝试的次数太多,已经不知道怎么复现了,不过就这三个问题应该能展现出来问题的奇葩性吧。
三、问题的解决
因为柔型数组的特性:即最后一个元素不占结构体总的大小。所以在传递时无法选择值传递的方式(即使这个函数的功能是查询,出于避免误操作数据的原因,并不希望将数据的地址传进去)。最后的解决办法是:一定要选择地址传递的方式,一定要选择地址传递的方式,一定要选择地址传递的方式。 说三遍都不足以表达我内心中跑过的羊驼数量。
测试地址的代码:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
typedef struct {
int length;
int cursor;
int data[0];
}order_table;
order_table* create_order_table(int length); //创建一个柔性数组
void check_order_table_length(order_table table, int *length); //返回柔性数组的长度
void free_order_table(order_table *table); //释放柔性数组的内存
void insert_order_table_element(order_table *table, int element); //向柔性数组里添加元素
void binary_search(order_table table, int element); //查找有序表中的元素
int main(void)
{
int table_length;
int table_index;
int element;
printf("Please enter the length of the ordered table:\n");
scanf("%d", &table_length);
order_table *table = create_order_table(table_length);
printf("Please enter the elements of the ordered table:\n");
for (table_index = 0; table_index < table_length; table_index++)
{
scanf("%d", &element);
printf("table_length:%d, insert before table_index:%d\n", table_length, table_index);
insert_order_table_element(table, element);
printf("table_length:%d, insert after table_index:%d\n", table_length, table_index);
}
for(table_index=0;table_index<table->length;)
{
printf("search index:%d, address:%p\n", table_index, &(table->data[table_index]));
printf("%d\n", table->data[table_index]);
table_index += 1;
}
printf("Please enter the element which you want to search:\n");
scanf("%d", &element);
binary_search(*table, element);
}
order_table* create_order_table(int length)
{
order_table* table = (order_table*)malloc(sizeof(order_table) + sizeof(int)*length);
table->length = length;
table->cursor = 0;
printf("in create_order_table:%p\n", table);
return table;
}
void check_order_table_length(order_table table, int *length)
{
*length = table.length;
}
void free_order_table(order_table *table)
{
free(table);
table = NULL;
}
void insert_order_table_element(order_table *table, int element)
{
printf("in insert_order_table_element:%p\n", table);
printf("\ninsert before:%d, address:%p\n", table->cursor, &(table->data[table->cursor]));
table->data[table->cursor] = element;
printf("insert element:%d\n", element);
(table->cursor)++;
printf("insert after:%d\n", table->cursor);
}
void binary_search(order_table table, int element)
{
printf("in binary_search:%p\n", table);
int temp_index;
int low = 0, high = table.length, middle;
int key;
int i;
for (i=0;i<table.length;i++)
{
printf("i:%d ", i);
printf("value:%d ", table.data[i]);
printf("address:%p\n", &(table.data[i]));
}
}
测试地址结果: 可以看到binary_search函数中各个数据的地址都是错误的,值也是错误的。
[root@localhost /]# ./main
Please enter the length of the ordered table:
5
in create_order_table:0x10d5ac0
Please enter the elements of the ordered table:
1 2 3 4 5
table_length:5, insert before table_index:0
in insert_order_table_element:0x10d5ac0
insert before:0, address:0x10d5ac8
insert element:1
insert after:1
table_length:5, insert after table_index:0
table_length:5, insert before table_index:1
in insert_order_table_element:0x10d5ac0
insert before:1, address:0x10d5acc
insert element:2
insert after:2
table_length:5, insert after table_index:1
table_length:5, insert before table_index:2
in insert_order_table_element:0x10d5ac0
insert before:2, address:0x10d5ad0
insert element:3
insert after:3
table_length:5, insert after table_index:2
table_length:5, insert before table_index:3
in insert_order_table_element:0x10d5ac0
insert before:3, address:0x10d5ad4
insert element:4
insert after:4
table_length:5, insert after table_index:3
table_length:5, insert before table_index:4
in insert_order_table_element:0x10d5ac0
insert before:4, address:0x10d5ad8
insert element:5
insert after:5
table_length:5, insert after table_index:4
search index:0, address:0x10d5ac8
1
search index:1, address:0x10d5acc
2
search index:2, address:0x10d5ad0
3
search index:3, address:0x10d5ad4
4
search index:4, address:0x10d5ad8
5
Please enter the element which you want to search:
4
in binary_search:0x500000005
i:0 value:1 address:0x7fff261f67f0
i:1 value:0 address:0x7fff261f67f4
i:2 value:0 address:0x7fff261f67f8
i:3 value:0 address:0x7fff261f67fc
i:4 value:639592512 address:0x7fff261f6800
[root@localhost /]#