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(内存地址)上存储的值。

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

相关推荐
Ni-Guvara5 分钟前
对象优化及右值引用优化(四)
开发语言·c++
Ddddddd_1582 小时前
C++ | Leetcode C++题解之第560题和为K的子数组
c++·leetcode·题解
夏天匆匆2过2 小时前
linux性能提升之sendmmsg和recvmmsg
linux·c++·单片机·网络协议·udp·tcp
Jack黄从零学c++3 小时前
设计模式——策略模式(c++)
c++·设计模式·策略模式
MinBadGuy3 小时前
【GeekBand】C++设计模式笔记10_Prototype_原型模式
c++·设计模式·原型模式
chengpei1473 小时前
51单片机使用NRF24L01进行2.4G无线通信
c语言·51单片机
日晨难再3 小时前
C语言&Python&Bash:空白(空格、水平制表符、换行符)与转义字符
linux·c语言·开发语言·python·bash
GeekAlice3 小时前
算法笔记/USACO Guide GOLD金组Graphs并查集Disjoint Set Union
c++·经验分享·笔记·学习·算法
阿巴~阿巴~4 小时前
C_数据结构(单链表算法题) —— 相交链表、环形链表I、环形链表II、随机链表的复制
c语言·开发语言·数据结构·算法·链表·1024程序员节
yangpipi-4 小时前
数据结构(C语言版)-2.栈和队列
c语言·开发语言·数据结构