为什么下é¢ä»£ç ä¸­çš„printf语å¥æ‰“å°ä¸€ä¸ªå€¼è€Œä¸æ˜¯åžƒåœ¾å€¼ï¼Ÿ

时间:2019-02-14 13:34:12

标签: c arrays pointer-arithmetic subscript-operator

int main(){
    int array[] = [10,20,30,40,50] ;
    printf("%d\n",-2[array -2]);
    return 0 ;
}

è°èƒ½è§£é‡Š-2 [array-2]的工作方å¼ï¼Œä¸ºä»€ä¹ˆåœ¨è¿™é‡Œä½¿ç”¨[]? 这是我分é…中的一个问题,它给出的输出为“ -10â€ï¼Œä½†æˆ‘ä¸æ˜Žç™½ä¸ºä»€ä¹ˆï¼Ÿ

4 个答案:

答案 0 :(得分:5)

从技术上讲,这会调用未定义的行为。引用C11,第6.5.6章

  

如果两个指针都   æ“作数和结果指å‘åŒä¸€æ•°ç»„对象的元素,或者指å‘最åŽä¸€ä¸ªæ•°ç»„的元素   数组对象的元素,求值ä¸åº”产生溢出;å¦åˆ™ï¼Œ   行为是ä¸ç¡®å®šçš„。 [....]

因此,(array-2)是未定义的行为。

但是,大多数编译器将读å–索引,并且å¯èƒ½èƒ½å¤Ÿä½¿+2å’Œ-2索引无效,[2[a]与a[2]相åŒï¼Œä¸Ž*(a+2)相åŒï¼Œå› æ­¤2[a-2]是*((2)+(a-2))],并且仅考虑è¦æ±‚值的其余表达å¼ï¼Œå³*(a)或a[0]。

然åŽï¼Œæ£€æŸ¥operator precedence

-2[array -2]实际上与-(array[0])相åŒã€‚因此,结果是值array[0]å’Œ- ved。

答案 1 :(得分:3)

这是一个ä¸å¹¸çš„教学示例,因为这æ„味ç€å¯ä»¥åšä¸€äº›é€šå¸¸åœ¨å®žè·µä¸­ä¸æ­£ç¡®çš„事情。

技术上正确的答案是该程åºå…·æœ‰æœªå®šä¹‰çš„行为,因此任何结果都是å¯èƒ½çš„,包括打å°-10,打å°ä¸åŒçš„数字,打å°å®Œå…¨ä¸åŒæˆ–根本ä¸æ‰“å°çš„东西,无法è¿è¡Œï¼Œå´©æºƒå’Œ/或执行æŸäº›æ“作完全无关。

未定义的行为æ¥è‡ªè¯„ä¼°å­è¡¨è¾¾å¼array -2的结果。 array从其数组类型衰å‡ä¸ºæŒ‡å‘第一个元素的指针。 array -2会指å‘ä½äºŽæ­¤ä½ç½®ä¹‹å‰ä¸¤ä¸ªä½ç½®çš„元素,但是没有这样的元素(并且这ä¸æ˜¯â€œå•ç«¯ç»“æŸâ€çš„特殊规则),因此无论如何评估,这都是一个问题它出现的上下文。

(C11 6.5.6 / 8说)

  

当将整数类型的表达å¼æ·»åŠ åˆ°æŒ‡é’ˆæˆ–从指针中å‡åŽ»æ—¶ï¼Œ....如果指针æ“作数和结果都指å‘åŒä¸€æ•°ç»„对象的元素,或者指å‘数组对象的最åŽä¸€ä¸ªå…ƒç´ ï¼Œè¯„ä¼°ä¸ä¼šäº§ç”Ÿæº¢å‡ºï¼›å¦åˆ™ï¼Œè¡Œä¸ºæ˜¯ä¸ç¡®å®šçš„。


现在,教师å¯èƒ½æ­£åœ¨å¯»æ‰¾çš„技术上ä¸æ­£ç¡®çš„答案是大多数实现中实际å‘生的事情:

å³ä½¿array -2ä¸åœ¨å®žé™…数组之外,它也会求值为数组数æ®èµ·å§‹åœ°å€å‰2*sizeof(int)个字节的æŸä¸ªåœ°å€ã€‚å–消引用该地å€æ˜¯æ— æ•ˆçš„,因为我们ä¸çŸ¥é“那里确实有int,但我们ä¸ä¼šã€‚

查看较大的表达å¼-2[array -2],[]è¿ç®—符比一元-è¿ç®—符具有更高的优先级,因此它表示-(2[array -2])而ä¸æ˜¯(-2)[array -2]。 A[B]的定义与*((A)+(B))相åŒã€‚通常将A用作指针值,将B用作整数值,但是åƒæˆ‘们在此处所åšçš„那样,以相åçš„æ–¹å¼ä½¿ç”¨å®ƒä»¬ä¹Ÿæ˜¯åˆæ³•çš„。所以这些是等效的:

-2[array -2]
-(2[array -2])
-(*(2 + (array - 2)))
-(*(array))

最åŽä¸€æ­¥çš„行为与我们预期的一样:将两个值添加到array - 2的地å€å€¼ä¹‹åŽæ˜¯2*sizeof(int)个字节,这使我们返回到第一个数组元素的地å€ã€‚å› æ­¤*(array)å–消引用该地å€ï¼Œç»™å‡º10,而-(*(array))å–消该值,给出-10。程åºæ‰“å°-10。


å³ä½¿æ‚¨åœ¨ç³»ç»Ÿå’Œç¼–译器上看到它“起作用â€ï¼Œä¹Ÿæ°¸è¿œä¸è¦æŒ‡æœ›è¿™ç§äº‹æƒ…。由于该语言无法ä¿è¯å°†è¦å‘生的一切,因此,如果您进行了似乎ä¸åº”该进行的微å°æ›´æ”¹ï¼Œæˆ–者在其他系统,ä¸åŒçš„编译器,相åŒç‰ˆæœ¬çš„åŒä¸€ç‰ˆæœ¬æˆ–使用åŒä¸€ç³»ç»Ÿå’Œå¦ä¸€å¤©çš„编译器。

答案 2 :(得分:1)

以下是-2[array-2]的评估方å¼ï¼š

首先,请注æ„,-2[array-2]被解æžä¸º- (2[array-2])。下标è¿ç®—符[...]的优先级高于一元-è¿ç®—符。我们ç»å¸¸å°†è¯¸å¦‚-2之类的常é‡è§†ä¸ºå•ä¸ªæ•°å­—,但实际上它是应用于-çš„{​​{1}}è¿ç®—符。

在2中,array-2自动转æ¢ä¸ºæŒ‡å‘其第一个元素的指针,因此它指å‘array。

然åŽarray[0]å°è¯•è®¡ç®—指å‘数组中第一个元素之å‰çš„两个元素的指针。 C标准未定义最终的行为,因为C 2018 6.5.6 8表示仅定义了指å‘数组æˆå‘˜å’Œæ•°ç»„末尾的算法。

仅出于说明目的,å‡è®¾æˆ‘们使用的C实现通过定义指针使用平é¢åœ°å€ç©ºé—´å¹¶å…许任æ„指针算术æ¥æ‰©å±•C标准。然åŽarray-2指å‘数组å‰é¢çš„两个元素。

然åŽarray-2使用C标准将2[array-2]定义为E1[E2]的事实。也就是说,下标è¿ç®—符是通过将这两件事相加并应用*((E1)+(E2))æ¥å®žçŽ°çš„。因此,哪个表达å¼ä¸º*和哪个表达å¼ä¸ºE1并ä¸é‡è¦ã€‚ E2与E1+E2相åŒã€‚å› æ­¤E2+E1是2[array-2]。加2将指针从数组之å‰çš„两个元素移回数组的开头。然åŽåº”用*(2 + (array-2))会在该ä½ç½®10产生元素。

最åŽï¼Œåº”用*得到-10。 (回想一下,åªæœ‰é€šè¿‡æˆ‘们的å‡è®¾ï¼Œå³C实现支æŒå¹³é¢åœ°å€ç©ºé—´æ‰èƒ½å¾—出此结论。您ä¸èƒ½åœ¨é€šç”¨C代ç ä¸­ä½¿ç”¨å®ƒã€‚)

答案 3 :(得分:0)

此代ç è°ƒç”¨æœªå®šä¹‰çš„行为,并且å¯ä»¥æ‰“å°ä»»ä½•å†…容,包括-10。

C17 6.5.2.1数组下标状æ€ï¼š

  

下标è¿ç®—符[]的定义是E1[E2]与(*((E1)+(E2)))相åŒ

å«ä¹‰array[n]等效于*((array) + (n)),这就是编译器评估下标的方å¼ã€‚这使我们能够åƒn[array]那样编写array[n]这样的愚蠢的混淆,等åŒäºŽ*((n) + (array))。因为*((array) + (n))等效于-2[array -2]。如此处所述:
With arrays, why is it the case that a[5] == 5[a]?

专门查看表达å¼[array -2]:

  • [array - 2]å’Œ[]自然是等效的。在这ç§æƒ…况下,å‰è€…åªæ˜¯è‰çŽ‡çš„æ ·å¼ï¼Œç›®çš„是为了混淆代ç ã€‚
  • æ“作员优先级告诉我们首先考虑-*( (2) + (array - 2) )。
  • 因此表达å¼ç­‰äºŽ-
  • 请注æ„,第一个2ä¸æ˜¯æ•´æ•°å¸¸é‡-的一部分。 Cä¸æ”¯æŒè´Ÿæ•´æ•°å¸¸é‡ 1),[]实际上是一元å‡è¿ç®—符。
  • 一元å‡è´Ÿçš„出现率比-2[低,因此[中的2会“绑定â€åˆ°(array - 2)。
  • æ ¹æ®C17 6.5.6 / 8:对å­è¡¨è¾¾å¼(2) + (array - 2)进行å•ç‹¬è¯„估并调用未定义的行为:

      

    将具有整数类型的表达å¼æ·»åŠ åˆ°æŒ‡é’ˆæˆ–从指针中å‡åŽ»æ—¶ï¼Œ   结果具有指针æ“作数的类型。 //-如果指针æ“作数和结果都指å‘åŒä¸€æ•°ç»„对象的元素,或者指å‘数组对象的最åŽä¸€ä¸ªå…ƒç´ ï¼Œåˆ™æ±‚值ä¸åº”产生溢出;å¦åˆ™ï¼Œè¡Œä¸ºæ˜¯ä¸ç¡®å®šçš„。

  • 推测而言,未定义行为的一ç§æ½œåœ¨å½¢å¼å¯èƒ½æ˜¯ç¼–译器决定将整个表达å¼array替æ¢ä¸º-*array,在这ç§æƒ…况下,整个表达å¼æœ€ç»ˆå°†ä»¥{{1 }}并打å°-10。

    没有ä¿è¯ï¼Œå› æ­¤ä»£ç æ˜¯é”™è¯¯çš„。如果为您分é…了解释代ç ä¸ºä½•æ‰“å°-10的作业,则您的è€å¸ˆæ— èƒ½ã€‚将混淆作为C语言研究的一部分进行研究ä¸ä»…毫无æ„义/有害,而且ä¾èµ–未定义的行为或期望其产生一定的结果也是有害的。


1) C更支æŒè´Ÿçš„整数常é‡è¡¨è¾¾å¼ã€‚ -2是整数常é‡è¡¨è¾¾å¼ï¼Œå…¶ä¸­2是类型int的整数常é‡ã€‚