【问题标题】:Find size of array without using sizeof不使用 sizeof 查找数组的大小
【发布时间】:2013-04-07 19:02:34
【问题描述】:

我正在寻找一种在 C 中不使用 sizeof 来查找数组大小的方法,我发现了以下代码:

int main ()
{
    int arr[100];
    printf ("%d\n", (&arr)[1] - arr);
    return 0;
}

谁能给我解释一下它是如何工作的?

【问题讨论】:

  • 没有理由不能使用sizeof
  • 看起来这个有 100 个元素的数组实际上被视为一个(未命名的)数组的第 0 项。
  • 不错的技巧,它也符合标准。
  • @effeffe:也许吧,但请看下面 Daniel 的 cmets。我认为它不符合标准,尽管我想不出一个很好的理由让它在实践中不起作用。减法,我的意思是——%d 的使用肯定不是严格遵守的,事实上在一个看起来相当正常的大端实现中会失败,一个 32 位 int 和一个 64 位 ptrdiff_t。跨度>
  • @SteveJessop 实际上你是对的,它可能不符合标准,让我们在那里进行讨论。但是,我同意它应该可以工作,但标准不能让我们取消引用实际上并不指向对象或其一部分的指针,这是有道理的。

标签: c arrays sizeof


【解决方案1】:

&arr 是一个指向 100 个 ints 的数组的指针。

[1] 的意思是“加上所指向的东西的大小”,它是一个由 100 个ints 组成的数组。

所以(&arr)[1]arr 之间的差是100 ints。

(请注意,此技巧仅适用于 sizeof 本来可以工作的地方。)

【讨论】:

  • [1] 并不意味着“添加指向的事物的大小”。这意味着“添加指向的事物的大小,然后取消引用结果指针”。
【解决方案2】:

&arr 给你一个指向数组的指针。 (&arr)[1] 等价于 *(&arr + 1)&arr + 1 为您提供指向 arr 后面的 100 个整数数组的指针。使用 * 取消引用它会为您提供后面的数组。由于此数组用于加法表达式 (-),因此它衰减为指向其第一个元素的指针。表达式中的arr 也是如此。所以你减去指针,一个指向arr 之后不存在的元素,另一个指向arr 的第一个元素。这给了你 100。

但它不起作用。 %d 用于int。指针差异返回您 ptrdiff_t 而不是 int。您需要将%td 用于ptrdiff_t。如果你对printf() 对你传递给它的参数类型撒谎,你会得到当之无愧的未定义行为。

编辑(&arr)[1] 可能导致未定义的行为。这并不完全清楚。如果有兴趣,请参阅下面的 cmets。

【讨论】:

  • (&arr)[1] - arr 不也是未定义的行为吗?
  • @DanielFischer C99:加法运算符:For the purposes of these operators, a pointer to an object that is not an element of an array behaves the same as a pointer to the first element of an array of length one with the type of the object as its element type. 所以,看起来这没问题。我的意思是[1] 部分。其余的和往常一样。
  • 但是第 8 段的最后一句是“如果结果指向数组对象的最后一个元素,则它不应用作一元 * 运算符的操作数,即评估。”如果我理解正确,(&arr)[1] 会评估*(&arr + 1) 中的*。如果您使用(&arr)[1] 的地址,或者将sizeof 应用于它,这不会评估*,但使用-,这没关系?
  • @DanielFischer:标准规定 &* 是无操作的,即使取消引用是 UB(C99 中的 6.5.3.2/3)。本着同样的精神,我们可能期望使用衰减指针代替&,但我认为您是正确的,标准中不能保证这一点。
  • @AlexeyFrunze 但是我们没有*(&E),我们有*(&E + 1)
【解决方案3】:

通常(根据视觉工作室), 对于数组 &arrarr 相同,它返回我们函数的起始基地址。

(&arr)[0] 只不过是&arrarr

例如:它会返回一些地址:1638116

现在,(&arr)[1] 表示我们开始访问数组,跳出表示下一个数组或当前数组大小的下一段(前 100 个)。

例如:它会返回一些地址:1638216

现在,减去(&arr)[1] - (&arr)[0]=100

【讨论】:

  • "(&arr)[0] 只不过是 &arrarr" -- arr&arr 有不同的类型时虽然两者都指向同一个位置。前者是int* 类型,而后者是int(*)[100] 类型。
【解决方案4】:

&variable 给出变量的位置(称为P
&variable + 1 给出变量旁边位置的地址。 (称之为N

(char*)N-(char*)P 给出NP 之间有多少个字符。由于每个字符都是 1 字节大小,所以上面的结果给出了字节数 PN。 (等于数组的大小,以字节为单位)。

同样, (char*) (a+1)-(char*)a; 以字节为单位给出数组中每个元素的大小。

所以数组中的元素个数 = (size of array in bytes)/(size of each element in the array in bytes)

#include<stdio.h>

int main()
{
    int a[100];
    int b = ((char*)(&a+1)-(char*)(&a));
    int c = (char*) (a+1)-(char*)a;
    b = b/c;
    printf("The size of array should be %d",b);
    return 0;

}

【讨论】:

    【解决方案5】:

    int arry[6]={1,2,3,4,5,6} //让数组元素为 6, 所以... 字节大小 = (char*)(arry+6)-(char *)(arry)=24;

    【讨论】:

    • OP 要求解释他的示例是如何工作的。你又举了一个例子。这不是 OP 问题的答案。
    【解决方案6】:
    int main ()
    {
      int arr[100];
      printf ("%d\n", ((char*)(&arr+1) - (char*)(&arr))/((char*) (arr+1) -(char*) (arr)));
      return 0;
    }
    

    【讨论】:

    • 虽然此代码可能会回答问题,但提供有关此代码为何和/或如何回答问题的额外上下文可提高其长期价值。
    • 如果您添加一些关于您的代码如何工作的解释,我将很乐意支持您的回答。顺便说一句,你应该使用%ld,而不是%d
    猜你喜欢
    • 1970-01-01
    • 2017-03-15
    • 2021-12-16
    • 2015-08-02
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多