3 - 语义“陷阱”篇

一、指针与数组

/* *(a+i) 等价于 a[i],当 i == 0 时,*a = a[0]
 * 因为 *(i+a) == *(a+i),所以 i[a] == a[i],但绝对不推荐这种写法,只是在此验证下
 * 
 * a 代表整个数组的时候只有两种情况,其余情况下,a 代表的都是数组首元素的地址
 * 1、sizeof(a)
 * 2、&a 
 */
int a[3] = {1,2,3};
printf("*(a+1):%d, a[1]:%d, 1[a]:%d\n"
  , *(a+1), a[1], 1[a]);  /* *(a+1):2, a[1]:2, 1[a]:2 */
#include <stdio.h>

int main()
{
  /* calendar 是一个拥有 12 个数组类型元素的数组,
   * 其中,每个元素又是一个拥有 31 个整型元素的数组
   */
  int calendar[12][31];
  int (*monthp)[31];
  int *dayp;

  for (monthp = calendar; monthp < &calendar[12]; monthp++)
    for (dayp = *monthp; dayp < &(*monthp)[31]; dayp++)
      *dayp = 0;

  return 0;
}

二、作为参数的数组声明

/* C 语言会自动将作为参数的数组声明转换为相应的指针声明,也就是说,如下两示例写法完全相同
 * 如此,在 C 语言中,我们没有办法将一个数组作为函数参数直接传递
 */
int strlen(char s[])
{
  /* ... */
}

int strlen(char *s)
{
  /* ... */
}

三、求值顺序

C 语言中,只有四个运算符(&&、||、?:、,)存在规定的求值顺序,其中,&& 和 || 先对左侧操作数求值,只有需要时才对右侧操作数求值;?: 有三个操作数,如 a?b:c,操作数 a 先被求值,再根据 a 的值求操作数 b 或 c 的值;而逗号运算符,先对左侧操作数求值,然后该值被 “丢弃”,再对右侧操作数求值(注意,分隔函数参数的逗号并非逗号运算符)

四、&&、||、!

&&、||、! 对操作数的处理方式是将其视作要么是 “真”,要么是 “假”,通常约定将 0 视作 “假”,而非 0 视作 “真”,最终运算结果只有 0 和 1

#include <stdio.h>

int main()
{
  int a = -1;
  int b = -1;
  int c = -1;

  a = !0;
  b = !1;
  c = !-1;

  printf("a:%d, b:%d, c:%d\n", a, b, c);  /* a:1, b:0, c:0 */

  a = 0 || 0;
  b = 1 || 0;
  c = 1 || 1;

  printf("a:%d, b:%d, c:%d\n", a, b, c); /* a:0, b:1, c:1 */

  a = 0 && 0;
  b = 1 && 0;
  c = 1 && 1;

  printf("a:%d, b:%d, c:%d\n", a, b, c); /* a:0, b:0, c:1 */

  return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值