C语言:指向结构体内元素的指针

3
为方便打印,我希望创建一个指向结构体元素的指针数组。要怎么做?我的尝试在结构体的最后一行中。需要注意的是,除了int之外,这个结构体还有其他值,在此未显示。我只想对int进行此类索引。
struct status {
    int lastinputVac;
    int inputVac;

    int outputVac;

    /* The unit is % */
    int outputpower;

    int outputHz;

    /* The unit is % */
    int batterylevel;

    int temperatureC;

    int *ordered_values[] = { &lastinputVac, &inputVac, &outputVac, &outputpower, &outputHz, &batterylevel, &temperatureC };
}

1
没事了 - 编辑后的代码更有意义;) - sonicwave
那么在结构体内创建这种索引的正确方式是什么? - Peter
虽然它使用了C++,但是我在之前的一个问题中发布的答案演示了一般思路。显然,您需要将std :: string更改为char *,并将cout更改为printf,但是使用offsetof获得的偏移数组是重要的,这将保持不变。 - Jerry Coffin
7个回答

1

所以问题是“我想创建一个指向结构体元素的指针数组”,并提到这些元素可能不是int类型。

我编写了一个通用解决方案,但在安全性、语言符合性和设计方面可能需要很多改进,但它展示了下面问题的一种解决方案。下面的代码计算结构体的大小,假设结构体的元素都是相同大小的,然后构造一个指向这些元素的指针数组,print_array函数通过迭代打印出这些元素。我也可以重载ostream<<运算符,但我想尽可能保持简单。

  #include "stdafx.h"

  struct status {
      int lastinputVac;
      int inputVac;
      int outputVac;

      /* The unit is % */
      int outputpower;

      int outputHz;

      /* The unit is % */
      int batterylevel;

      int temperatureC;
};

//template<typename T>
#include <vector>
#include <algorithm>
#include <iostream>
#include <iterator>

// hide this into a library 
template<typename T>
size_t build_array(const status& val, T*** vecptr)
{
const size_t _size = sizeof(status) / sizeof(int);
*vecptr = (T**)malloc( sizeof(T*) *_size );

for (size_t i = 0; i < _size; ++i) {
    (*vecptr)[i] = ((T *)((&val)+i));
}
return _size;
}

template<typename T>
void free_array(T** vecptr)
{
free(vecptr);
}

template<typename T>
void print_array(T **vecptr, size_t size) 
{
for (size_t i = 0; i < size; i++)
    std::cout << *(*vecptr + i) << std::endl;
}

//T1 is the type of the struct and T2 is the type of the elements
template<typename T1, typename T2>
class PrintStruct
{
private:
    T2 **m_vecptr;
    size_t m_size;

public:
    PrintStruct(T1 t) {
        m_size = build_array<T2>(t, &m_vecptr);
        print_array(m_vecptr, m_size);
    }

    ~PrintStruct() {
        free_array(m_vecptr);
    }
 };

 int _tmain(int argc, _TCHAR* argv[])
 {
 status _status;
 _status.batterylevel = 1;
 _status.inputVac = 2;
 _status.lastinputVac = 3;
 _status.outputHz = 4;
 _status.outputpower = 5;
 _status.outputVac = 6;
 _status.temperatureC = 7;

 PrintStruct<status, int> _ps(_status);
 return 0;
 }

我同意。 :) 我会发布另一个解决方案。 - ervinbosenbacher
使用宏替换模板非常容易。核心部分用C语言编写(编译为c++)。只需一行代码,您就可以轻松地打印一个结构,前提是满足约束条件。 - ervinbosenbacher

1

不妨硬着头皮写一些额外的代码,以便通过结构成员访问来打印它。为了节省几行代码而损害设计是得不偿失的。

想象一下,有一天你必须在库中公开这个结构体。你真的想用这个毫无实际意义的指针数组来负担用户吗?


我能理解你的观点,并且在某种程度上同意。但我仍然很好奇如何去做。 - Peter

0

这样是不可能的。

C++ 中有成员指针(“相对”指针)的概念,这正是你真正需要的。

在你的情况和 C 中,我建议始终使用 int 数组并仅命名索引。

struct status {
   int values[7];
}
..
const int lastinputVac = 0;  // or upper case when you like, or use #define
..
status a;
a.values[lastinputVac] = 27;
int z = a.values[lastinputVac];

你明白我的意思吗?
顺便说一下,你可以使用 union 来实现这两种方法, 提供一个按名称编译访问的方式和通过数组索引的方式。

0

你不能独立于结构体变量实例获取结构体成员的地址;也就是说,你需要做类似以下的操作:

struct status foo;
int *ordered_values[] = {&foo.lastInputVac, &foo.inputVac, ...};

然而,考虑到您的所有结构成员都是int,您可以进行一些类型转换,就像这样

int *ordered_values = (int *) &foo;
for (i = 0; i < 7; i++)
  printf("%d\n", ordered_values[i]);

这个应该可以工作;结构体实例的地址与其第一个成员的地址相同,而且由于所有成员都是int,所以不应该有任何对齐或填充问题。我不建议这种做法,但对于您的目的来说,它应该足够好。


仅显示了结构体的一部分。我还在其中有其他变量。但是仅需要这样的索引以用于整数。谢谢! - Peter
@PeterSenna:在这种情况下,请忽略我所写的内容;如果不是所有的东西都是相同类型,那么这个例子就行不通了。 - John Bode

0

从您的评论中看来,您的结构体有很多元素,但您只想打印其中一些。以下是我的想法:

1)不要将此数组放入结构体中!它是静态的--对于任何struct status,它永远不会改变,因此将其放在结构体中是浪费和不直观的。

2)您是否考虑将这些值分离到它们自己的结构体中?然后您可以使用以下范例:

enum status {
    LASTINPUT_VAC,
    INPUT_VAC,
    OUTPUT_VAC,
    OUTPUT_PWR,
    OUTPUT_HZ,
    BATT_LVL,
    TEMPERATURE,
    STATUS_MAX
};

struct system {
    char name[MAXNAME];
    long other_data;
    float coords[2];
    char *whatever_you_have_here;
    int status[STATUS_MAX];
};

然后要打印/使用其中一个,您可以通过引用它来实现:

struct system sys;
int temp = sys.status[TEMPERATURE];
for (int i = 0; i < STATUS_MAX; i++)
    printf("%d\n", sys.status[i]);

这可能不完全符合您的需求,但我只是想提供另一种在C语言中完成此类事情的方式。干杯!


0

我脑海中浮现出另一种方法。 我的观察是,成员顺序正确,但您可能希望通过索引轻松访问。

但要注意:您必须关注填充。填充可能会使int类型的数据错位。但是,在int32的情况下,我不会预期出现问题。

有些人认为这太过于hacky,但这是一种可能性。

struct status {
  int lastinputVac;
  int inputVac;

  int outputVac;

/* The unit is % */
  int outputpower;

  int outputHz;

  /* The unit is % */
  int batterylevel;

  int temperatureC;
} stat;

int* a = &stat;

int maxIndex = (&stat.temperatureC - &stat.lastinputVac) / sizeof (stat); // should be 6
 // you could build named constants for that
a[0]; // lastinputVac
a[1]; // inputVac
a[2]; // outputVac
a[3]; // outputpower
a[4]; // outputHz
a[5]; // batterylevel
a[6]; // temperatureC

0

将结构体与数组合并。请查阅您的编译器文档以了解对齐方式。

union {

    struct {
       int someInt0;
       int someInt1;    
    }; //anonymous

    int arry[2];

} thing;

~

val0 = thing.someInt0; //structure access
val1 = thing.arry[0]; //gcc, C18, XC8, and XC32 handle this with the top value indexed to 0

if (val0 == val1) { 
    puts("this works");
}

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接