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也可以设置signed和unsigned。

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

字面量后缀

int x = 123;

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

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

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

  1. int x = 123L;

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

八进制和十六进制的值,也可以使用后缀l和L指定为 Long 类型,比如020L和0x20L。

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

int x = 123U;

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

int x = 123LU;

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

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

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

  • f和F:float类型。
  • l和L:对于整数是long int类型,对于小数是long double类型。
  • ll和LL:Long Long 类型,比如3LL。
  • u和U:表示unsigned int,比如15U、0377U。 u还可以与其他整数后缀结合。

溢出

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

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

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

上面示例中,变量x加1,得到的结果不是256,而是0。因为x是unsign 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);

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

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

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

上面示例中,函数内部的变量a是int类型,但是返回的值是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(内存地址)上存储的值。

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

相关推荐
C^h5 小时前
c++ string
开发语言·c++
听风说ml5 小时前
socket编程 【C语言】
c语言·udp·tcp·socket编程
raindayinrain5 小时前
c++高性能--原子操作,无锁编程,操作顺序
开发语言·c++·性能优化
学逆向的5 小时前
C++ 合并命名空间
开发语言·c++·网络安全
Zhao-Jichao5 小时前
VS2026 打包 C++ 程序生成 EXE,借助 Installer Project 扩展工具
开发语言·c++
学逆向的6 小时前
C 局部静态变量
c语言·开发语言·网络安全
小徐不徐说7 小时前
C++ 接口与插件设计:从工厂注册到 Qt 动态插件
数据库·c++·qt·系统架构·程序设计
大都督会赢的7 小时前
C++第一节课
开发语言·c++
UIU1147 小时前
P1233 [ICPC 2001 Taejon R] 木棍加工
数据结构·c++·算法·动态规划
TMedical7 小时前
MedPlanning 截骨模拟矫形功能
c++·图像处理·人工智能·qt·健康医疗