是否可以指向数据变量?我知道我可以拥有指向字符串的指针,例如char * str [n]我可以在那些指针上执行'for'循环来检索字符串... str [i]其中i是索引计数器。
如果我有一些数据,例如
char var1;
int var2;
char var3;
我想从stdin获取数据我可能会使用3次单独调用scanf() - 只是一个例子 - 来填充这些变量。
我可以拥有'数据指针数组',例如void * data []其中data [0] = char var1,data [1] = int var2和data [2] = char var3,这样我就可以在'for'循环中使用scanf()的单个调用填充这些变量? (我假设类型必须是无效的,以满足数组中的不同类型)
答案 0 :(得分:3)
我不是真的推荐这个,但这是你描述的实现:
char var1;
int var2;
char var3;
void *vars[3];
char *types[3];
vars[0]=&var1; types[0]="%c";
vars[1]=&var2; types[1]="%d";
vars[2]=&var3; types[2]="%c";
for (int i=0;i<3;i++)
{
scanf(types[i],vars[i]);
}
您需要类型数组,以便scanf知道它应该期待什么。
但是,这个程序非常不安全。通过丢弃任何类型安全性,您可以从错误输入中邀请崩溃。此外,如果您错误配置类型[],那么您几乎肯定会崩溃,或者看到意外的结果。
当你设置数组时,你真的保存过任何代码吗?
这里有很多答案可以让你使用类型安全的C ++解决方案,或者像其他人推荐的那样,明确地调用scanf()。
答案 1 :(得分:2)
你当然可以拥有这样一个void * data []数组。但是,您无法读取via scanf中的那些内容,因为您需要为不同的数据类型使用不同的格式说明符。
如果你想这样做,你可以迭代一个数组
struct dataType
{
void *data;
char *format_specifier;
}
或者某些。但是,我怀疑这是一个好主意 - 你可能也想提示每个值,所以你要为该结构添加另一个char *提示符,以后你可能还需要其他东西。< / p>
我怀疑你最后编写的代码要比简单地扫描 n 时更加努力,即使是非常大的 n 。 / p>
答案 2 :(得分:0)
不直接,不。如果你能够在这种情况下使用C ++,那么你最接近的就是将每个变量包装在一个对象中(类似于variant_t或一些模板化的多态解决方案)。例如,我相信你可以这样做:
class BaseType
{
public:
virtual void DoScanf();
};
template<typename TYPE>
class SubType : public BaseType
{
public:
SubType(const TYPE& data) : m_data(data) {}
const TYPE& m_data;
virtual void DoScanf()
{
// Your code here
}
};
int num1;
char char1;
SubType<int> num1Wrapper(num1);
SubType<char> char1Wrapper(char1);
// You can then make a list/vector/array of BaseTypes and iterate over those.
答案 3 :(得分:0)
问题是这个void *数组将处理不同大小的数据类型。对于这个问题,您可能希望使用结构并维护其中的数组。或者您可以将数据作为字节数组放入,但是您必须知道如何正确地“切断”数据。
答案 4 :(得分:0)
你可以有一个void *数组,所以* array [0] = var1等等。
答案 5 :(得分:0)
说明问题..
int main(int argc, char* argv[])
{
char var1 = 'a';
int var2 = 42;
char var3 = 'b';
void* stuff[3] = {0};
stuff[0] = &var1;
stuff[1] = &var2;
stuff[2] = &var3;
// Can't really use the array of void*'s in a loop because the
// types aren't known...
assert( var1 == (char)(*(char*)stuff[0]));
assert( var2 == (int)(*(int*)stuff[1]));
assert( var3 == (char)(*(char*)stuff[2]));
return 0;
}
答案 6 :(得分:0)
看起来你正在尝试在C中实现一个等效的模板(C ++):对于我的一个项目来说,这正是我想要做的事情。我认为我的情况不那么令人困惑,因为我只使用一种数据类型(一些项目特定的结构),我的数组不会混合数据类型。
嘿,做一件事尝试使用你打算使用的各种数据类型的联合,我认为阅读这个不应该是一个问题。当您使用该联合的读取函数读取它时,将能够读取它,因为继承了C类型的安全性。我在这里的意思是遵循我们通常用来检查机器的字节顺序的相同概念
这些是很少的想法,我自己正在努力,应该能够完成这一天或两天。只有这样我才能告诉你,如果这是完全可能的话。祝你好运,如果你正在为某个项目实施这个。分享你的解决方案,可能在这里,我也可能找到答案。 :)
我正在使用void指针数组。
答案 7 :(得分:0)
如果你想要一个可以是“任何东西”的变量数组并且你在C中工作,那么我认为你想要一个包含typeid和union的结构。
像这样,也许:(注意,快速示例,未经过编译测试,不是完整的程序)
struct anything_t {
union {
int i;
double d;
char short_str[7]; /* 7 because with this and typeid makes 8 */
char *str; /* must malloc or strdup to use this */
}; /* pretty sure anonymous union like this works, not compiled */
char type; /* char because it is small, last because of alignment */
};
char *anything_to_str(char *str, size_t len, const struct anything_t *any)
{
switch(any->type) {
case 1: snprintf(str, len, "%d", any->i); break;
case 2: snprintf(str, len, "%f", any->d); break;
case 3: snprintf(str, len, "%.7s", any->short_str); break; /* careful, not necessarily 0-terminated */
case 4: snprintf(str, len, "%s", any->str); break;
default: abort(); break;
}
return str;
}
我忘了添加我想要的scanf部分:
char *scanf_anything(struct anything_t *inputs, size_t count)
{
int input_i;
struct anything_t *i;
for(input_i=0; input_i<count; ++input_i) {
any = inputs + input_i;
switch(any->type) {
case 1: scanf(" %d ", any->i); break;
case 2: scanf(" %lf ", any->d); break;
case 3: scanf(" %.6s ", any->short_str); break;
case 4: scanf(" %a ", any->str); break; /* C99 or GNU but you'd be a fool not to use it */
default: abort(); break;
}
}
}
答案 8 :(得分:0)
这里提出的所有使用void *的解决方案都存在同样的问题。将void *作为可变参数(如scanf)传递,它期望另一种类型的指针将您置于“未定义行为”域中(出于同样的原因,您应该在作为可变参数传递时将NULL转换为正确的类型)。
在大多数常见平台上,我认为编译器没有理由利用它。所以它可能会有效,直到编译器制造商发现SPEC中有一个测试,它允许获得0.000001%的改进: - )
在一些充满异国情调的平台上,充分利用这一点是显而易见的事情(毕竟已经为他们制定了规则;他们大多只是历史兴趣,但我不打算任何关于嵌入式平台的事情;我知道,在嵌入式平台上使用scanf可以被认为是奇怪的事情)
答案 9 :(得分:0)
上述所有解决方案均有效,但尚未提及您可以通过一次简单的scanf调用完成所需的操作:
scanf(%c%d%c",var1,var2,var3);