【问题标题】:Better way of declaring an array?声明数组的更好方法?
【发布时间】:2012-07-17 02:37:53
【问题描述】:

我正在用 C 语言编写并使用 GCC 进行编译。

有没有更好的方法来声明积分。我很惊讶地看到点是一个数组。有什么方法可以声明点,让它看起来更像一个数组。

typedef struct Span
{
    unsigned long lo;
    unsigned long hi;
} Span;

typedef struct Series
{
    unsigned long *points;
    unsigned long count;
    unsigned long limit;
} Series;

void SetSpanSeries(Series *self, const Span *src)
{
    unsigned long *points;

    if (src->lo < src->hi )
    {

        // Overlays second item in series.
        points = self->points;  // a pointer in self structure
        points[0] = src->lo;
        points[1] = src->hi;
        self->count = 1;
    }
}

现在让我们说点指向一个数组结构。

typedef struct Span
{
    unsigned long lo;
    unsigned long hi;
} Span;


span *points[4];

现在我该如何编写这些代码行?我做对了吗?

points = self->points;  // a pointer in self structure
points[0].lo = src->lo;
points[0].hi = src->hi;

【问题讨论】:

  • 尽量避免将制表符粘贴到代码块中。他们往往会弄乱格式。
  • +1 因为我的答案最终比我想象的要长得多。
  • 当我复制这些标签时,它们的行为有点奇怪。下次我必须摆脱标签。
  • 不,鉴于声明 unsigned long *points;points不是一个数组。它是一个指针(因为你是这样声明的)。它可能恰好指向数组的第一个元素。强烈建议阅读:comp.lang.c FAQ 的第 6 节。

标签: c arrays syntax


【解决方案1】:

使用声明unsigned long *pointspoints 是一个指针。它指向数组的开头。 arr[x]*(arr + x) 相同,所以arr 是一个数组(在这种情况下,它获取数组的地址,添加x,并取消引用'指针')还是一个指针(其中在这种情况下,它获取指针值,添加 x,并取消引用指针),arr[0] 仍然获得相同的数组访问权限。

在这种情况下,您不能将 points 声明为数组,因为您没有将它使用作为数组 - 您将它用作指向数组的指针.指针是浅拷贝 - 如果更改指针指向的数据,它会更改原始数据。要创建常规数组,您需要进行深层复制,这将防止您在pointer 中的更改影响数组self,这最终是您想要的。

事实上,你可以在没有points 的情况下重写整个事情:

void SetSpanSeries(Series *self, const Span *src)
{
    if (src->lo < src->hi )
    {
        self->points[0] = src->lo;
        self->points[1] = src->hi;
        self->count = 1;
    }
}

至于你的第二个例子,是的,points[0].lo 是正确的。 points-&gt;lo 也是正确的,只要您只访问 points[0]。 (或者self-&gt;points[0].lo,如果你完全去掉points。)

【讨论】:

  • 快 58 秒并且更有说服力。好的。 :)
  • "它指向一个数组" - 严格来说它指向数组的第一个元素。这与数组在内存中的地址相同,但指向数组的指针与指向该数组的元素的指针是不同的类型。通常你可以将两者混为一谈而不会造成麻烦,但初学者仍然需要知道它们是两个不同的东西。
  • 谢谢你的解释帮助很大。
【解决方案2】:

将指针视为数组的能力肯定会让大多数 C 初学者感到困惑。当作为参数传递给函数时,数组甚至衰减指向指针,给人的印象是数组和指针是完全可以互换的——它们不是。 Expert C Programming: Deep C Secrets 中有一个很好的描述。 (这是我最喜欢的书之一;如果你想了解 C,强烈推荐。)

无论如何,写pointer[2]*(pointer+2) 相同——数组语法对大多数人来说更容易阅读(和写作)。

由于您使用此 *points 变量来提供对另一个内存块的更轻松访问(struct Series 中的指针 points),您不能为您的局部变量使用数组因为您不能将数组的基数重新分配给其他东西。考虑以下非法代码:

int foo[10];
int *bar;
int wrong[10];

bar = foo; /* fine */
wrong = foo; /* compile error -- cannot assign to the array 'wrong' */

重写此代码的另一个选择是删除临时变量:

if (src->lo < src->hi) {
    self->points[0] = src->lo;
    self->points[1] = src->hi;
    self->count = 1;
}

我不确定临时变量是否有助于提高易读性——它只是节省了输入几个字符,但代价是添加了 很多 个字符。 (也是一个令人困惑的变量。)

【讨论】:

  • C 对我来说不是那么直观。认为这本书对初学者很有价值。我正在使用 C 的喜悦:Miller 和 Quilici 的 C 编程
  • 我认为Expert C Programming 是一本优秀的第二 书。这对于第一本书来说太过分了。我认为second edition of The C Programming Language 可能是最好的第一本书。我不熟悉The Joy Of C,但description on the Wiley website 听起来已经足够好了,而且Wiley 通常是一本好书。
  • 我收到了“专家 C 编程:深度 C 秘密”。看起来很有趣。作者有幽默感。谢谢你的建议。
【解决方案3】:

在中间部分,您说点是指向结构跨度的指针的数组 4。在第三部分中,您从 self->points 分配点(意味着点的先前值,该数组,已丢失)。然后,您可以取消引用点,就好像它是一个 struct Span 数组,而不是一个指向 struct Span 的指针数组。

在其他作品中,这无法编译,因为您正在混合类型,即使您没有混合类型,您也会覆盖由 points 变量的定义分配的内存。

提供系列的定义可能有助于解释发生了什么。

但在第一个示例中,点数可能应该是Span *points,但如果没有看到系列,我们无法确定。

【讨论】:

  • 我添加了结构系列和结构跨度。
  • @historystamp:嗯,我猜更好,但现在我们需要知道 self->points 是如何创建的。仍然没有解释类型不匹配的问题。
猜你喜欢
  • 2011-02-07
  • 1970-01-01
  • 2020-10-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多