【问题标题】:C: sizeof struct of structs to find number of elements in structC: sizeof struct of structs 查找结构中元素的数量
【发布时间】:2020-08-28 13:35:55
【问题描述】:

我有两个结构:

struct point {
  double x;
  double y;
  const char *description;
};

struct geomap {
  struct point points[];
};

假设我将 x 个点添加到新地图中。我如何从 sizeof 开始得到那个数字 x?或者有没有其他方法可以知道我在新地图中添加了多少点?我需要一个循环来删除点并做其他事情,但我无法计算出元素的数量。

我试过了

sizeof(m->points[])/sizeof(m->points[0])

但它说:ERR 预期表达式 如果您想更快地玩一些代码:

static int counter = 0;

struct geomap *geomap_new() {
  struct geomap *a_geomap = (struct geomap *)malloc(sizeof(geomap));
  if (!a_geomap)
    exit(0);
  struct point *a_point = (struct point *)malloc(sizeof(point));
  if (!a_point)
    exit(0);
  return a_geomap;
}

int geomap_add_point(struct geomap *m, double x, double y, const char *descr) {
  m->points[counter].x = x;
  m->points[counter].y = y;
  m->points[counter].description = descr;
  counter++;
  if (!m) {
    printf("failed to allocate new point");
    return 0;
  }
  return 1;
}

int main() {
  struct geomap *m = geomap_new();
  geomap_add_point(m, 10324, 2341213.2, "212222");
  geomap_add_point(m, 103212, 221341.2, "21wdd2");
  geomap_add_point(m, 103241, 2.2, "2213122");
  geomap_add_point(m, 1034123, 23341.2, "1111");
  geomap_add_point(m, 1000324213, 23234242341.2, "dediowd");

  return 1;
}

【问题讨论】:

  • 在这个例子中,结构中总是有 0 个点。尽管结构中有 0 个点,但您的代码写入了第 1、2、3、4 和 5 个点,从而覆盖了一些不属于您的内存。
  • 这是什么struct point *a_point = ...
  • 非常感谢大家的回答,他们都非常有用!

标签: c struct sizeof


【解决方案1】:

首先,您应该考虑数组是否是用于此容器的正确数据类型。如果您打算经常添加/删除项目,那么链表或图表可能更合适。

至于struct point points[];,这就是所谓的灵活数组成员。它只能放在结构的末尾,并且结构旁边需要有其他成员。一个灵活的数组成员被认为是一个不完整类型的数组,所以你不能在它上面使用sizeof,因为它的大小在编译时是未知的。您必须手动跟踪大小。

正确的用法应该是这样的:

struct geomap {
  size_t size;
  struct point points[];
};

struct geomap *geomap_new(size_t def_size) {
  struct geomap *obj = malloc( sizeof *obj + sizeof(struct point[def_size]) );
  obj->size = def_size;
  ...
    

也就是说,你一次性为对象和灵活数组分配内存。

【讨论】:

    【解决方案2】:

    首先,这不是一个最小可重现的例子。

    你有一些错误/错别字。

    错误 #1:

    /* ... */
    struct geomap *a_geomap = (struct geomap *)malloc(sizeof(geomap));
    /* ... */
    struct point *a_point = (struct point *)malloc(sizeof(point));
    /* ... */
    

    您在这里尝试分配地理地图内的点数组,对吗?见malloc(/*size in bytes*/)。猜猜这段代码应该是这样的:

    int i = 0;
    /* ... */
    struct geomap *a_geomap = (struct geomap *)malloc(sizeof(struct geomap));
    a_geomap->points = (struct point *)malloc(sizeof(struct point) * /* Maximum number of points here */ )
    /* ... */
    

    错误 #2:

    int geomap_add_point(struct geomap *m, double x, double y, const char *descr) {
      m->points[counter].x = x;
      m->points[counter].y = y;
      m->points[counter].description = descr;
      counter++;
      if (!m) {
        printf("failed to allocate new point");
        return 0;
      }
      return 1;
    }
    

    你应该在这里检查你是否超过了数组的大小。否则你可能会得到 SIGSEGV(分段错误)。应该是什么:

    int geomap_add_point(struct geomap *m, double x, double y, const char *descr) {
      if (!m) {
        printf("No geomap!!!");
        return -1;
      }
      // Here check for size
      if (counter >= /* Maximum number of points here */) {
        printf("No space for new point!!!");
        return -1;
      }
      m->points[counter].x = x;
      m->points[counter].y = y;
      m->points[counter].description = descr;
      ++counter;
      return 0;
    }
    

    最后……

    警告 #1:

    您应该考虑常见的做法,我们通常在错误时从函数返回 负值,在成功时返回

    附:简短的回答:如果你有一个静态数组,那么count = (sizeof(/*array*/) / sizeof(/*element type*/)) 应该可以工作。 但是! 这将更新使用动态数组。仅限动态数组cound = /*Number of elements*/

    例子:

    /* For static array: */
    
    #define MAX_ARR_T_DATA_SIZE 100
    /* ... */
    struct arr_t {
      int data[MAX_ARR_T_DATA_SIZE];
    };
    /* ... */
    arr_t array;
    int count = sizeof(struct array) / sizeof(int);
    
    
    /* For dynamic array: */
    
    #define MAX_ARR_T_DATA_SIZE 100
    /* ... */
    struct arr_t {
      int* data;
    };
    /* ... */
    arr_t array;
    array.data = (int*)malloc(sizeof(int) * MAX_ARR_T_DATA_SIZE);
    int count = MAX_ARR_T_DATA_SIZE;
    

    附言另外我建议您阅读有关动态数组的信息。例如: http://www.mathcs.emory.edu/~cheung/Courses/255/Syllabus/2-C-adv-data/dyn-array.html

    【讨论】:

    • Re“你不允许这样分配数组。您需要指定大小”:C 标准允许将结构类型中的数组定义为 struct point points[];。它必须是最后一个成员,并且必须至少有一个其他命名成员。此类结构的内存可以动态分配,并且该结构的行为就像它包含一个与分配的内存允许的一样大的数组。
    • @EricPostpischil 是的,对不起。我的错。固定
    【解决方案3】:

    在这个例子中,结构中总是有 0 个点。

    尽管结构中有 0 个点,但您的代码写入了第 1、2、3、4 和 5 个点,从而覆盖了一些不属于您的内存。

    所以你可以通过使用数字0来获得积分。

    如果你想分配一个包含一些点的地图,你可以这样做:

    struct geomap *a_geomap = (struct geomap *)malloc(sizeof(geomap) + NUMBER_OF_POINTS*sizeof(point));
    

    由您决定如何存储NUMBER_OF_POINTS。例如,您可以决定它始终为 10。或者您可以将另一个int 添加到struct geomap 以存储该号码。

    请注意,数组在创建后无法调整大小。永远。

    【讨论】:

    • "请注意,数组在创建后无法调整大小。永远。"在这种情况下,您可以简单地重新分配。不是最有效的方法,但完全有可能。
    • @Lundin realloc 分配了一个新数组,该数组的地址可能与旧数组相同,也可能不同
    猜你喜欢
    • 2023-01-04
    • 1970-01-01
    • 1970-01-01
    • 2014-10-19
    • 1970-01-01
    • 1970-01-01
    • 2011-06-09
    • 1970-01-01
    • 2012-03-03
    相关资源
    最近更新 更多