C学习(6)

字节(Byte): 一个字节由8个相邻的二进制位组成,每个位由0或1组成。字节是计算机技术中最小的可操作存储单位。一个字节的整数范围是0~255

整数 int

int类型的大小。比较常见的是使用4个字节(32位)存储一个int类型的值,但是2个字节(16位)或8个字节(64位)也有可能使用。它们可以表示的整数范围如下。

  • 16位:-32,768 到 32,767。
  • 32位:-2,147,483,648 到 2,147,483,647。
  • 64位:-9,223,372,036,854,775,808 到 9,223,372,036,854,775,807。

对于int类型,默认是带有正负号的,也就是说int等同于signed int

int类型表示非负整数时,就必须使用关键字unsigned声明变量。

  1. unsigned int a; //16位的范围为 0到 65535
  2. int a; //16位的范围为-32,768 到 32,767。

字符类型char也可以设置signedunsigned

  1. signed char c; // 范围为 -128 到 127
  2. unsigned char c; // 范围为 0 到 255

字面量后缀

int x = 123;

上面代码中,x是变量,123就是字面量。

编译时,字面量也会写入内存,因此编译器必须为字面量指定数据类型,就像必须为变量指定数据类型一样。

比如,编译器将一个整数字面量指定为int类型,但是程序员希望将其指定为long类型,这时可以为该字面量加上后缀lL,编译器就知道要把这个字面量的类型指定为long

  1. int x = 123L;

这里123L写成123l,效果也是一样的,但是建议优先使用L,因为小写的l容易跟数字1混淆。

八进制和十六进制的值,也可以使用后缀lL指定为 Long 类型,比如020L0x20L

如果希望指定为无符号整数unsigned int,可以使用后缀uU

int x = 123U;

LU可以结合使用,表示unsigned long类型。LU的大小写和组合顺序无所谓。

int x = 123LU;

对于浮点数,编译器默认指定为 double 类型,如果希望指定为其他类型,需要在小数后面添加后缀f(float)或l(long double)。

  1. 1.2345e+10F
  2. 1.2345e+10L

总结一下,常用的字面量后缀有下面这些。

  • fFfloat类型。
  • lL:对于整数是long int类型,对于小数是long double类型。
  • llLL:Long Long 类型,比如3LL
  • uU:表示unsigned int,比如15U0377Uu还可以与其他整数后缀结合。

溢出

每一种数据类型都有数值范围,如果存放的数值超出了这个范围(小于最小值或大于最大值),需要更多的二进制位存储,就会发生溢出。蹲个屁股,不详细阐述。

一般来说,编译器不会对溢出报错,会正常执行代码,但是会忽略多出来的二进制位,只保留剩下的位,这样往往会得到意想不到的结果。所以,应该避免溢出。

  1. unsigned char x = 255;
  2. x = x + 1;
  3. printf("%d\n", x); // 0

上面示例中,变量x1,得到的结果不是256,而是0。因为xunsign char类型,最大值是255(二进制11111111),加1后就发生了溢出,256(二进制100000000)的最高位1被丢弃,剩下的值就是0

函数的参数和返回值,

会自动转成函数定义里指定的类型。

  1. int dostuff(int, unsigned char);
  2. char m = 42;
  3. unsigned short n = 43;
  4. long long int c = dostuff(m, n);

上面示例中,参数变量mn不管原来的类型是什么,都会转成函数dostuff()定义的参数类型。

下面是返回值自动转换类型的例子。

  1. char func(void) {
  2. int a = 42;
  3. return a;
  4. }

上面示例中,函数内部的变量aint类型,但是返回的值是char类型,因为函数定义中返回的是这个类型。

指针 *

字符*表示指针。指针是什么?首先,它是一个值,这个值(*)代表一个内存地址,因此指针相当于指向某个内存地址的路标。指针变量就是一个普通变量,只不过它的值是内存地址

通常跟在类型关键字的后面,表示指针指向的是什么类型的值。比如,char*表示一个指向字符的指针,float*表示一个指向float类型的值的指针。

  1. int* intPtr;

上面声明了一个变量intPtr,它是一个指针(指针变量?),指向的内存地址存放的是一个整数。

*可以放在变量名与类型关键字之间的任何地方,下面的写法都是有效的。

  1. int *intPtr;
  2. int * intPtr;
  3. int* intPtr;

* 运算符

*这个符号除了表示指针以外,还可以作为运算符,用来取出指针变量所指向的内存地址里面的值。 *取地址里的值

  1. void increment(int* p) { //指针变量
  2. *p = *p + 1; //取值
  3. }

上面示例中,函数increment()的参数是一个整数指针p。函数体里面,*p就表示指针p所指向的那个值。对*p赋值,就表示改变指针所指向的那个地址里面的值。

变量地址而不是变量值传入函数,还有一个好处。对于需要大量存储空间的大型变量,复制变量值传入函数,非常浪费时间和空间,不如传入指针来得高效。

& 运算符

& 运算符用来取出一个变量所在的内存地址。&取地址,*取地址里的值

  1. int x = 1;
  2. printf("x's address is %p\n", &x);

上面示例中,x是一个整数变量,&x就是x的值所在的内存地址。printf()%p是内存地址的占位符,可以打印出内存地址。

指针小节中,参数变量加1的函数,可以像下面这样使用。

  1. void increment(int* p) {
  2. *p = *p + 1;
  3. }
  4. int x = 1;
  5. increment(&x);
  6. printf("%d\n", x); // 2

上面示例中,调用increment()函数以后,变量x的值就增加了1,原因就在于传入函数的是变量x的地址&x

&运算符与*运算符互为逆运算,下面的表达式总是成立。

  1. int i = 5;
  2. if (i == *(&i)) // 正确 &取地址,*取地址里的值

例子:

* 的区别:

x 是指针变量,存储的内存地址

*x 是取值操作,获得x(内存地址)上存储的值。

以下这个好像才是标准写法?

相关推荐
XiaoCCCcCCccCcccC7 小时前
多路复用 select -- select 的介绍,select 的优缺点,select 版本的 TCP 回显服务器
服务器·c++
XiaoCCCcCCccCcccC7 小时前
多路复用 poll -- poll 的介绍,poll 的优缺点,poll 版本的 TCP 回显服务器
服务器·网络·c++
奔跑吧邓邓子8 小时前
【C语言实战(72)】C语言文件系统实战:解锁目录与磁盘IO的奥秘
c语言·文件系统·目录·开发实战·磁盘io
小π军8 小时前
STL利器:upper_bound与lower_bound的使用
c++
Zx623659 小时前
13.泛型编程 STL技术
java·开发语言·c++
The Last.H9 小时前
Educational Codeforces Round 185 (Rated for Div. 2)A-C
c语言·c++·算法
caron49 小时前
C++ 推箱子游戏
开发语言·c++·游戏
路过君_P10 小时前
C++ 算法题解:迷宫寻路
c++·算法·深度优先
止观止10 小时前
告别“祖传C++”:开启你的现代C++之旅
c++·c++11·c++20·编程思想·现代c++