✨小细节

C语言书写灵活,既可以一行多句,也可以一句多行,且每行不加行号。

编译过程

每个C语言程序写完后,都是先预编译、编译,后链接,最后运行。(.c—->.s—>.obj—->.exe)这个过程中注意.c、.s和.obj文件时无法运行的,只有.exe文件才可以运行。

标识符

  • 关键字
  • 预定义标识符 main、define、scanf、printf、include、type 都不是关键字
  • 用户标识符;If也不是关键字(C语言标识符大小写敏感)

    赋值

    注意:

  • 逗号表达式级别最低,表达式最右边的那个表示表达式的数值 ```c int n1=n2=10; // 错误,C语言不能连续定义并赋值,会报“n2未定义”

int x1=0,x1=0 x1=x2=5;//赋值表达的值是最右边数a的值5

n=m+2//是a=a(m+2)

j=a++;//等价于j=a;a=a+1; j=++a;//等价于a=a+1;j=a;

int a=1,b=2; printf(“%d\n”,a=a+1,a+6,b+2); //2 printf(“%d”,3,4,5); //3 printf(“%d”,(3,4,5)); //5,逗号表达式级别最低,表达式最右边的那个表示表达式的数值

  1. <a name="iKrRp"></a>
  2. # 数值
  3. <a name="q2TZF"></a>
  4. ## 整型数据
  5. 整型常量就是正常数。在c语言中,使用的整常数有八进制、十六进制和十进制三种。在程序中是根据前缀来区分各种进制数的。<br />1) 八进制整常数:必须以0开头。数码取值为0~7.<br />2) 十六进制整常数:前缀为0X或0x。数码取值为09,AF或a~f。<br />3) 整型常数的后缀:在16位字长的机器上,基本整型长度也为16位,因此表示的数的范围也是有限定的。十进制无符号整常数的范围为065535,有符号数为-32768+32767.八进制无符号数的表示范围为0X00XFFFF或0x00xFFFF。如果使用的数超过了上述范围,就必须用长整型数来表示。长整型数使用后缀“L”或“l”来表示的。
  6. **易错题:**
  7. ```c
  8. int a=011;
  9. printf("%d\n",++a); //11

实型(浮点型)

在程序运行过程中可以改变其值的实型量被称为实型变量,实型变量根据数值的范围可分为

  • 单精度(float)
  • 双精度(double)
  • 长双精度(long double)

3种类型。

double x=1,y;
y=x+3/2;
printf("%f\n",y); // 2.000000
double d;
float f;
long l;
int i;
i=f=l=d=20/3;
printf("%d %ld %f %lf\n",i,l,f,d); // 6 6 6.000000 6.000000

实现保留三位小数

float x = 12.34567;
float y = (int)(x*1000+0.5)/1000.0; //保留三位小数,第四位四舍五入

十进制数形式

由数码0~9和小数点组成。(必须有小数点)

指数形式

由十进制数,加阶码标志“e“或”E”以及阶码。
2.33e-1是合法,数据为2.33*10-1(应试口诀:e前e后必有数,e后必为整数)

逻辑运算

  • 异或^:不同为1,相同为零
  • 与&:同1则1,有零则零
  • 或|:同零则零,有1则1
  • 非!:每位都取反

    真和假

    非0为真,0为假。

    程序结构

  • 顺序结构

  • 循环结构
    • do while
    • while
    • for
  • 选择结构

    • if else
      • 多句if语句需加{}
    • switch
      • switch只能和break一起使用不能和continue一起使用
      • switch(x)中x是整型常量、字符型常量、枚举型数据,不能是变量
      • switch后小括号里面的表达式不能为实型(浮点型)
      • case后表达式不能是变量

        标准输入输出

  • scanf

    • 不能接收空格、制表符Tab、回车等;
    • 当遇到回车,空格和tab键会自动在字符串后面添加’\0’,但是回车,空格和tab键仍会留在输入的缓冲区中。
    • 不能指定浮点数的精度,如scanf("%3.2d",&a);是错误的
  • gets
    • 能够接收空格、制表符Tab和回车等
    • 可接受回车键之前输入的所有字符,并用’\0’替代 ‘\n’.回车键不会留在输入缓冲区中
  • int puts(const char *str):把一个字符串写入到标准输出 stdout,直到空字符,但不包括空字符。换行符会被追加到输出中。
  • int putc(int char, FILE *stream):在输出字符串时会将’\0’自动转换成’\n’进行输出,也就是说,puts方法输出完字符串后会自动换行。
  • int getchar(void):从标准输入 stdin 获取一个字符(一个无符号字符)
  • int putchar(int char):把参数 char 指定的字符(一个无符号字符)写入到标准输出 stdout 中。
    scanf("%d%d*d%d",&a,&b,&c);//跳过第输入的第三个数
    
    printf("%2d",123);    //第二部分有三位,大于指定的两位,原样输出123
    printf("%5d",123);      //第二部分有三位,小于指定的五位,左边补两个空格  123
    printf("%10f",1.25);    //小数要求补足6位的,没有六位的补0,。结果为  1.250000 
    printf("%5.3f",125);    //小数三位,整个五位,结果为1.250(小数点算一位)
    printf("%3.1f",1.25); //小数一位,整个三位,结果为1.3(要进行四舍五入)
    //□表示空格
    printf("y=%-8ld\n",y); //y=-43456□□
    printf("y=%-08ld\n",y);//y=-43456□□
    printf("y=%08ld\n",y); //y=-0043456
    printf("y=%+8ld\n",y); //y=-□□43456
    
    | 格式说明 | 表示内容 | | —- | —- | | %d | 整型 int | | %ld | 长整型 long int | | %f | 浮点型 float | | %lf | double | | %% | 输出一个百分号 | | %5d |
    | | %c | 字符 char | | %s | 字符串 | | %o | 八进制 | | %#o | 带前导的八进制 | | %X | 十六进制 | | %#X | 带前导的十六进制 |

强制类型转换

(int) a,注意类型上一定有括号

数组(重点)

数组名表示第一个元素的地址,数组名不可以自加,它是地址常量名。

一维数组

数组元素个数

int length = sizeof(a) / sizeof(a[0]);

二维数组

  • C语言允许在定义二维数组时不指定第一维的长度(即行数),但必须指定第二维的长度(即列数)。
  • 单纯定义数组时,所有维的长度都必须给出。

    字符数组/字符串

    定义

  • 字符串必须使用双引号 "",遇到 '\0' 字符串结束。

  • 字符数组首地址不能改变,不能用”=”直接赋值,即 s="Good News!" 是不合法的。
  • 字符数组中的内容不一定是字符串,还以是转移字符 \0
    // 赋值方式一
    char b[5];
    strcpy(b,"abcd");
    // 赋值方式二
    char b[5]={'a','b','c','d'};
    // 赋值方式三
    char *b="abcd";
    

    比较 strcmp

strcmp 函数是 string compare (字符串比较) 的缩写,用于比较两个字符串并根据比较结果返回整数。基本形式为 strcmp(str1,str2)

  • str1==str2,则返回零
  • str1<str2,则返回负数
  • str1>str2,则返回正数

    拷贝 strcpy

    ```c

    include

    include

int main() { char src[40]; char dest[100];

memset(dest, ‘\0’, sizeof(dest)); strcpy(src, “This is runoob.com”); strcpy(dest, src);

printf(“最终的目标字符串: %s\n”, dest); // 最终的目标字符串: This is runoob.com

return(0); }

<a name="EOQ3G"></a>
### 连接函数 `strcat`
```c
#include <stdio.h>
#include <string.h>

int main ()
{
   char src[50], dest[50];

   strcpy(src,  "This is source");
   strcpy(dest, "This is destination");

   strcat(dest, src);

   printf("最终的目标字符串: |%s|", dest); // 最终的目标字符串:This is destinationThis is source 
   return(0);
}

strlensizeof 的区别

strlen 统计字符长度不包括 \0
sizeof 统计字符长度包括 \0,长度*数据类型的空间大小。

各个数据类型的空间大小:

  • int:不说明就是 4 字节
    • long int:4 个字节
    • short int:2 个字节
  • char:1个字节
  • float:4个字节
  • double:8个字节
  • 汉字:一般都为2个字节

    逻辑运算符

    三种逻辑运算符号的优先级:! > && > ||
    ||、&& 运算符的短路现象
    a++||b++,如表达式a++的值非零,则表达式b++不再执行
    “||”运算符:若运算符左边为true,则不再对运算符右侧进行运算
    “&&”运算符:若运算符左侧为false则不再对右侧语句进行判断
    表示比0大且比10小的方法
    不能用 0<x<10,应是 (0<x)&&(x<10)

    函数

  • 函数是具有一定功能的程序块

  • 是C语言的基本组成单位
  • 函数不能嵌套定义函数
  • 函数默认类型为int

    main函数

    main是有且只有一个,是程序的入口

    实参,形参

  • 形参出现在函数定义中,在整个函数体内都可以使用, 离开该函数则不能使用。

  • 实参出现在主调函数中,进入被调函数后,实参变量也不能使用。

4bed2e738bd4b31c4655e52b8ad6277f9e2ff831.png

参数默认值

C语言不允许设置参数默认值,C++可以设置参数默认值。设置参数默认值有以下注意点:

  • 函数默认值一般写在声明中
  • 函数的默认值必须设置为局部变量
  • 函数的默认值必须设置为从右向左依次赋值
  • 默认值只能赋值一次

    # include<stdio.h>
    int f1(int x, int y=2) {
      return x*y;
    }
    int main() {
      printf("%d\n", f1(1,2));
    }
    

    自定义函数

    用户自定义函数包含两个部分,即声明部分和执行部分。声明部分在前,执行部分在后,这两个部分顺序不能颠倒,也不能有交叉。

    static 函数

    将一个函数说明为 static 后,该函数将只能被同一源文件中的函数调用,不能被其他源文件中的函数调用

    作用域

  • 局部变量:在函数内或者复合语句内定义的变量,作用域是它的函数内,共三种类型:

    • 自动:auto,自动变量随函数的使用与否创建消失
    • 存储器:register,分配在CPU中,没有内存地址
    • 静态:static,变量在全局数据区分配内存空间;编译器自动对其初始化。其作用域为局部作用域,当定义它的函数结束时,其作用域随之结束
  • 全局变量:函数外定义的变量,作用域从定义它的位置到整个程序运行结束,全局变量都是静态变量。 ```c

    include

void fn(void) { int n = 10;

printf("n=%d\n", n);
n++;
printf("n++=%d\n", n);

}

void fn_static(void) { static int n = 10;

printf("static n=%d\n", n);
n++;
printf("n++=%d\n", n);

}

int main(void) { fn(); //n=10 n++=11 fn_static(); //static n=10 n++=11 fn(); //n=10 n++=11 fn_static(); //static n=11 n++=12 return 0; }

<a name="m26fO"></a>
# 指针(重点)
<a name="XwaD4"></a>
## 数组指针和指针数组
```c
int (*arrPtr)[10] = NULL;   // 一个指针,它指向一个有10个int元素的数组
char *myStrPtr[10]; // char指针的数组

二级指针

int x=7;
int*p=&x,**q=p;

问你:p为多少?q为多少?q为多少?
7 p 7
再问你:
q=&x的写法可以吗?
不可以,因为二级指针只能存放一级指针的地址。

void 类型指针

  • void 类型指针所指向的数据类型不是确定的,或者说,可以是任何类型的。void 类型指针中的数据不能访问,如果非要访问的话,可以通过显式转换将 void 类型指针转换为与所指向的数据类型相符的类型。
  • 任何类型的指针都可以显式转换为 void 类型,且不会丢失数据。
  • void 类型指针可以通过显式转换为具有更小或相同存储对齐限制的指针,但数据可能失真。
  • 如果将void类型的指针转换为具有更大存储对齐限制的指针时,则会产生无效值。
    short a=23;
    void *p1;
    int *p2;
    p1=(void *)&a;
    p2=(int *)p1;
    printf("%d\n",*p2); // 其返回值为-859045865
    

    函数指针

    指针函数的用法 (*f)() ```c int add(int x,int y) { //…code }

void main() { int(f)(); f=add; } / 赋值后,合法的调用方式为 1、add(2,3) 2、f(2,3) 3、(f)(2,3) /

<a name="VcgAb"></a>
# 动态分配

- malloc(size):创建size个字节的连续存储空间void*类型
- calloc(n,size):创建n个同类型的连续存储空间
- free(p):释放动态分配的存储单元
```c
#include <stdlib.h>

int main()
{
    int *p1=(int*)malloc(sizeof(int));
    int *p2=(int*)calloc(10,sizeof(int));
    free(p1);
    free(p2);
    return 0;
}

结构体(重点)

写代码必须的,每年都会考C语言的代码,结构体的定义是最基本的操作

结构体变量所占字节数为其所有成员所占字节数之和

#include <stdlib.h>

int main()
{
    struct Stu
    {
        char name[10];
        char *p;
        int age;
    }stu1,*stu2;
    // 三种成员变量的引用方法
    stu1.age;
    stu2->age;
    (*stu2).age;
    return 0;
}

共用体

课程里可能有讲到但是不是每个特性的都很清楚,认真看一下这种数据结构的特性

  • 共用体变量所占内存长度等于里面所占内存最大的那个成员的长度。
  • 使用共用体变量的目的是希望用同一个内存段存放几种不同类型的数据,但请注意,在每一个瞬间只能存放其中一种,而不是同时存放几种。
  • 能够访问的是共用体变量中最后一次被赋值的成员,在对一个新的成员赋值后原有的成员就失去作用。
  • 共用体变量的地址和它各成员的地址都是同一个地址。
  • 不能对共用体变量名赋值。不能企图引用变量名来得到一个值。不能在定义共用体变量时对它初始化。不能用共用体变量名作为函数参数。 ```c

    include

    include

union Data { int i; float f; char str[20]; };

int main( ) { union Data data;

data.i = 10; data.f = 220.5; strcpy( data.str, “C Programming”);

printf( “data.i : %d\n”, data.i); printf( “data.f : %f\n”, data.f); printf( “data.str : %s\n”, data.str);

return 0; }

<a name="yxsSN"></a>
# 文件
`FILE *fopen(const char *filename, const char *mode)`<br />参数

- **filename** -- 这是 C 字符串,包含了要打开的文件名称。
- **mode** -- 这是 C 字符串,包含了文件访问模式,模式如下:
| **模式** | **描述** |
| --- | --- |
| "r" | 打开一个用于读取的文件。该文件必须存在。 |
| "w" | 创建一个用于写入的空文件。如果文件名称与已存在的文件相同,则会删除已有文件的内容,文件被视为一个新的空文件。 |
| "a" | 追加到一个文件。写操作向文件末尾追加数据。如果文件不存在,则创建文件。 |
| "r+" | 打开一个用于更新的文件,可读取也可写入。该文件必须存在。 |
| "w+" | 创建一个用于读写的空文件。 |
| "a+" | 打开一个用于读取和追加的文件。 |

```c
#include <stdio.h>
#include <stdlib.h>

int main()
{
   FILE * fp;
   fp = fopen ("file.txt", "w+");
   fprintf(fp, "%s %s %s %d", "We", "are", "in", 2014);
   fclose(fp);
   return(0);
}
//让我们使用下面的程序查看上面文件的内容:

#include <stdio.h>

int main ()
{
   FILE *fp;
   int c;

   fp = fopen("file.txt","r");
   while(1)
   {
      c = fgetc(fp);
      if( feof(fp) )
      { 
          break ;
      }
      printf("%c", c);
   }
   fclose(fp);
   return(0);
}

fgetc(FILE *fp):从指定的流 stream 获取下一个字符(一个无符号字符),并把位置标识符往前移动。该函数以无符号 char 强制转换为 int 的形式返回读取的字符,如果到达文件末尾或发生读错误,则返回 EOF。

#include <stdio.h>

int main ()
{
   FILE *fp;
   int c;

   fp = fopen("file.txt","r");
   while(1)
   {
      c = fgetc(fp);
      if( feof(fp) )
      {
          break ;
      }
      printf("%c", c);
   }
   fclose(fp);
   return(0);
}

fputc(char c,FILE *fp):把参数 char 指定的字符(一个无符号字符)写入到指定的流 stream 中,并把位置标识符往前移动。如果没有发生错误,则返回被写入的字符。如果发生错误,则返回 EOF,并设置错误标识符。

#include <stdio.h>

int main ()
{
   FILE *fp;
   int ch;

   fp = fopen("file.txt", "w+");
   for( ch = 33 ; ch <= 100; ch++ )
   {
      fputc(ch, fp);
   }
   fclose(fp);

   return(0);
}
  • fgets(char s,int n,FILE fp):从指定文件中读取一个字符串到字符数值中
  • fputs(char s,FILE fp):将字符串写入指定文件中
  • freed(char ps,int len,int n,FILE fp):从指定文件中一次读取n*len个数据块到内存缓冲区的数据项
  • fwrite(char ps,int len,int n,FILE fp):将指定的内存缓冲区的数据项写入指定文件中
  • fprintf(fp,format,arg1,arg2,…,argn):将输出项[arg1,…,argn]按指定格式写入指定文本中,遇到空格和换行时结束
  • fscanf(fp,format,arg1,arg2,…,argn):按指定格式从指定文本中读出数据到[arg1,…,argn]中,遇到空格和换行时结束
  • feof(FILE *fp):如果文件指针指到文件末尾返回值为非0,否则返回0
  • ferror(FILE *fp):操作错误返回非0,否则返回0
  • fseek(FILE *fp,long n,int mode):将某个文件的读写指针从某个位置移动到另一个位置
    • 相对文件头移动时,mode取值0或SEEK_SET
    • 相对文件尾部移动时,mode取值2或SEEK_END
    • 相对文件当前位置移动时,mode取值1或SEEK_CUR
  • rewind(FILE *fp):将指定文件的读写指针移至文件头
  • ftell(FILE *fp):返回指定文件指针的字节数

    预处理

C语言对预处理命令的处理是在编译阶段进行的,不是C语言语句,不需要加分号,不占执行时间。宏替换是简单的文本替换。如#define f(x) (x)*(x)#define f(x) x*x替换f(2+2)是有区别的,前者是(2+2)*(2+2)后者是2+2*2+2

大多数预处理器指令属于下面3种类型:

  • 宏定义:#define 指令定义一个宏,#undef指令删除一个宏定义。
  • 文件包含:#include指令导致一个指定文件的内容被包含到程序中。
  • 条件编译:#if,#ifdef,#ifndef,#elif,#else和#dendif指令可以根据编译器可以测试的条件来将一段文本包含到程序中或排除在程序之外。

剩下的#error,#line和#pragma指令更特殊的指令,较少用到。

标准函数库

常用库函数

  • sqrt() :算数平方根
  • abs():求int类型绝对值
  • fabs():求double类型绝对值函数
  • fabsf():求float类型绝对值函数
  • pow():幂函数

    qort 快速排序

    #include <stdlib.h>
    void qsort(void *base, size_t nitems, size_t size, int (*compar)(const void *, const void*))
    

    参数

  • base — 指向要排序的数组的第一个元素的指针。

  • nitems — 由 base 指向的数组中元素的个数。
  • size — 数组中每个元素的大小,以字节为单位。
  • compar — 用来比较两个元素的函数。

示例

#include <stdio.h>
#include <stdlib.h>

int values[] = { 88, 56, 100, 2, 25 };

int cmpfunc (const void * a, const void * b)
{
   return ( *(int*)a - *(int*)b );
}

int main()
{
   int n;

   printf("排序之前的列表:\n");
   for( n = 0 ; n < 5; n++ ) {
      printf("%d ", values[n]);
   }

   qsort(values, 5, sizeof(int), cmpfunc);

   printf("\n排序之后的列表:\n");
   for( n = 0 ; n < 5; n++ ) {
      printf("%d ", values[n]);
   }

  return(0);
}

fmax 两数最大值

#include<math.h>
#include <stdio.h>
#include <math.h>

int main(void)
{
    printf("fmax(2,1)    = %f\n", fmax(2,1));
    printf("fmax(-Inf,0) = %f\n", fmax(-INFINITY,0));
    printf("fmax(NaN,-1) = %f\n", fmax(NAN,-1));
}

附录

输入输出

  • %d 十进制有符号整数
  • %ld 十进制有符号长型整数
  • %u 十进制无符号整数
  • %x 无符号以十六进制表示的整数
  • %o无符号以八进制表示的整数
  • %#o 带前导码(数值前加0) 以八进制表示的整数
  • %hu unsigned short格式输出整数
  • %f 浮点数
  • %s 字符串
  • %c 单个字符
  • %p 指针的值
  • %e 指数形式的浮点数
  • %g 自动选择合适的表示法

    ASCII 码

Dec
(十进制)
缩写/字符 解释
48 0 字符0
65 A 大写字母A
97 a 小写字母a
32 (space) 空格

转移字符

转义字符 意义 ASCII码值(十进制)
\a 响铃(BEL) 007
\b 退格(BS) ,将当前位置移到前一列 008
\f 换页(FF),将当前位置移到下页开头 012
\n 换行(LF) ,将当前位置移到下一行开头 010
\r 回车(CR) ,将当前位置移到本行开头 013
\t 水平制表(HT) (跳到下一个TAB位置) 009
\v 垂直制表(VT) 011
\\ 代表一个反斜线字符’’\‘ 092
\‘ 代表一个单引号(撇号)字符 039
\“ 代表一个双引号字符 034
\? 代表一个问号 063
\0 空字符(NUL) 000
\012 换行 10
\ddd 1到3位八进制数所代表的任意字符 三位八进制
\xhh 十六进制所代表的任意字符 十六进制

各个类型占空间大小

数据类型 32位 64位 取值范围(32位)
char 1 1 -128~127
unsigned char(当byte使用) 1 1 0~255
short int /short  2 2 –32,768~32,767
unsigned short   2 2 0~65,535
int 4 4 -2,147,483,648~2,147,483,647
unsigned int 4 4 0~4,294,967,295
long int /long 4 8 –2,147,483,648~2,147,483,647
unsigned long 4 8 0~4,294,967,295
long long int/long long 8 8 -9,223,372,036,854,775,808
~9,223,372,036,854,775,807
指针  4 8
float   4 4 3.4E +/- 38 (7 digits)
double 8 8 1.7E +/- 308 (15 digits)

运算符的优先级与结合规则(重难点、易错)

易错题目
(1)执行下列语句int a=8; a+=a-=a*a; 后,a的值是 -112 (+=、-=、/=是从右到左结合)
(2)4>3&&7<5-!0 的值为0(运算符优先级-》>》&&)

主要看结合规则从右到左的运算符,从右到左的结合率的运算符经常出题。

优先级 运算符 名称或含义 使用形式 结合方向 说明
1 [] 数组下标 数组名[常量表达式] 左到右
() 圆括号 (表达式)
函数名(形参表)
. 成员选择(对象) 对象.成员名
-> 成员选择(指针) 对象指针->成员名
2 - 负号运算符 -表达式 右到左 单目运算符
(类型) 强制类型转换 (数据类型)表达式
++ 自增运算符 ++变量名
变量名++
单目运算符
自减运算符 —变量名
变量名—
单目运算符
* 取值运算符 *指针变量 单目运算符
& 取地址运算符 &变量名 单目运算符
! 逻辑非运算符 !表达式 单目运算符
~ 按位取反运算符 ~表达式 单目运算符
sizeof 长度运算符 sizeof(表达式)
3 / 表达式 / 表达式 左到右 双目运算符
* 表达式*表达式 双目运算符
% 余数(取模) 整型表达式%整型表达式 双目运算符
4 + 表达式+表达式 左到右 双目运算符
- 表达式-表达式 双目运算符
5 << 左移 变量<<表达式 左到右 双目运算符
>> 右移 变量>>表达式 双目运算符
6 > 大于 表达式>表达式 左到右 双目运算符
>= 大于等于 表达式>=表达式 双目运算符
< 小于 表达式<表达式 双目运算符
<= 小于等于 表达式<=表达式 双目运算符
7 == 等于 表达式==表达式 左到右 双目运算符
!= 不等于 表达式!= 表达式 双目运算符
8 & 按位与 表达式&表达式 左到右 双目运算符
9 ^ 按位异或 表达式^表达式 左到右 双目运算符
10 | 按位或 表达式|表达式 左到右 双目运算符
11 && 逻辑与 表达式&&表达式 左到右 双目运算符
12 || 逻辑或 表达式||表达式 左到右 双目运算符
13 ?: 条件运算符 表达式1? 表达式2: 表达式3 右到左 三目运算符
14 = 赋值运算符 变量=表达式 右到左
/= 除后赋值 变量/=表达式
*= 乘后赋值 变量*=表达式
%= 取模后赋值 变量%=表达式
+= 加后赋值 变量+=表达式
-= 减后赋值 变量-=表达式
<<= 左移后赋值 变量<<=表达式
>>= 右移后赋值 变量>>=表达式
&= 按位与后赋值 变量&=表达式
^= 按位异或后赋值 变量^=表达式
|= 按位或后赋值 变量|=表达式
15 , 逗号运算符 表达式,表达式,… 左到右

C语言各个类型所占字节数

类型 16位 32 位 64位
char 1 1 1
short int 2 2 2
int 2 4 4
unsigned int 2 4 4
float 4 4 4
double 8 8 8
long 4 4 8
long long 8 8 8
unsigned long 4 4 8

参考

【1】C 语言程序设计教程(第2版)杨有安 曹慧雅
【2】C 语言程序设计教程(第2版)王敬华