gpt4 book ai didi

c - 这个函数返回什么?

转载 作者:行者123 更新时间:2023-11-30 20:49:46 24 4
gpt4 key购买 nike

如果我正确解释这一点,它会将两个(长)整数作为输入,创建一个数组,然后减去该数组和一个整数,但我认为我无法减去数组和整数。

这个函数实际上返回什么?

int *ivector (long nl, long nh)
/* allocate an int vector with subscript range v[nl..nh] */
{
int *retval;

retval = malloc(sizeof(int)*(nh-nl+1));

return retval - nl;
}

最佳答案

在探索这个 ivector() 函数的行为之前,我们先回顾一下有关 C 语言中数组和指针的一些基本事实。

考虑代码

int a[10];
for(i = 0; i < 10; i++)
a[i] = 100 + i;

这会在内存中产生一个数组,我们可以这样想:

    +-----+-----+-----+-----+-----+-----+-----+-----+-----+-----+
a: | 100 | 101 | 102 | 103 | 104 | 105 | 106 | 107 | 108 | 109 |
+-----+-----+-----+-----+-----+-----+-----+-----+-----+-----+
0 1 2 3 4 5 6 7 8 9

假设我们现在说

int *ip = a;

由于 correspondence between arrays and pointers in C ,这相当于说

int *ip = &a[0];

无论如何,我们最终都会得到一个指向 a 的第一个单元格的指针,如下所示:

    +-----+
ip: | * |
+--|--+
|
v
+-----+-----+-----+-----+-----+-----+-----+-----+-----+-----+
a: | 100 | 101 | 102 | 103 | 104 | 105 | 106 | 107 | 108 | 109 |
+-----+-----+-----+-----+-----+-----+-----+-----+-----+-----+

现在,指针算术:当您向指针添加一个整数时,您“移动”了指针,使其指向底层数组中的下一个元素。确保您了解此代码打印数字 102 的所有不同方式:

int *ip2 = ip + 2;
printf("%d %d %d %d\n", *(ip + 2), ip[2], *ip2, ip2[0]);

(如果您理解所有四个表达式 *(ip+2)ip[2]*ip2ip2[0] 如何计算为数字 102,请阅读此内容或询问。这是“数组与指针对应关系”的另一个方面,也是我们理解 ivector 函数的基础。)

指针减法也有效:调用

printf("%d %d\n", *(ip2 - 1), ip2[-1]);

打印 101,两种略有不同的方式。

现在,让我们看一下 ivector() 函数。它试图帮助我们模拟不一定从 0 开始的数组。如果我们打电话

int a2 = ivector(0, 9);
for(i = 0; i <= 9; i++) a2[i] = 100 + i;

我们最终会得到一个几乎与之前一模一样的数组:

    +-----+
a2: | * |
+--|--+
|
v
+-----+-----+-----+-----+-----+-----+-----+-----+-----+-----+
| 100 | 101 | 102 | 103 | 104 | 105 | 106 | 107 | 108 | 109 |
+-----+-----+-----+-----+-----+-----+-----+-----+-----+-----+

唯一的区别是数组本身没有名称:这是我们通过调用 malloc 获得的匿名内存区域。

现在假设我们调用

int a3 = ivector(-5, 5);
for(i = -5; i <= 5; i++) a3[i] = 100 + i;

现在我们得到了一个 11 元素的“数组”,我们可以认为它看起来像这样:

    +-----+
a3: | *-----------------------------+
+-----+ |
v
+-----+-----+-----+-----+-----+-----+-----+-----+-----+-----+-----+
| 95 | 96 | 97 | 98 | 99 | 100 | 101 | 102 | 103 | 104 | 105 |
+-----+-----+-----+-----+-----+-----+-----+-----+-----+-----+-----+
-5 -4 -3 -2 -1 0 1 2 3 4 5

请注意,我们可以讨论 a3[0]a3[3]a3[-2] 等,就像这是一个下限为 -5 的常规数组一样。关键是您所询问的 ivector 末尾的减法:

return retval - nl;

这不会从数组的值中减去任何东西,或者任何东西;又是指针算术,从指针值 nl 中减去 retval 。对于调用 ivector(-5, 5) ,这会转换为

return retval - -5;

这当然相当于

return retval + 5;

因此我们得到了指向分配区域的 5 个元素的指针。

现在假设我们调用

int *a4 = ivector(1, 10);
for(i = 1; i <= 10; i++) a4[i] = 100 + i;

这就是一切崩溃的地方。目的是我们最终得到这样的图片:

    +-----+
a4: | * |
+--|--+
|
v
+-----+-----+-----+-----+-----+-----+-----+-----+-----+-----+
| 101 | 102 | 103 | 104 | 105 | 106 | 107 | 108 | 109 | 110 |
+-----+-----+-----+-----+-----+-----+-----+-----+-----+-----+
1 2 3 4 5 6 7 8 9 10

但是有一个非常明显的问题:a4实际上并没有指向分配的数组

基于指针算术的工作方式,以及传统上由简单的编译器为简单的计算机体系结构实现的方式,您可以说服自己这段代码“应该”工作,并且您可以访问 a4[1] , a4[2] , ... 直到 a4[10] 。当然,如果您尝试访问 a4[0] ,将会出现可怕的问题,但没关系,您不应该这样做,因为 a4 是一个基于 1 的数组。

不幸的是,最后一段代码不能保证工作。如果您计算的指针指向数组(您声明的实际数组,或者通过调用 malloc 获得的类似数组的内存块)“外部”,则指针算术定义。如果您尝试计算这样的指针,则行为是未定义的,即使您从未尝试访问越界指针指向的内存。因此,大多数知识渊博的 C 程序员都会建议您不要编写类似 ivector 的代码(或者如果您这样做,则只为 nl <= 0 调用它......但这当然很大程度上违背了目的)。

关于c - 这个函数返回什么?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/58557926/

24 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com