类型和变量命名
C语言为什么要有类型
类型是编程语言中一项非常基础的概念。它是用来描述数据的种类或数据类型的,可以是基本类型,如整数、浮点数、字符等,也可以是由基本类型组成的复合类型,如数组、结构体等。类型的存在有以下几个作用:
1. 内存分配:不同类型的数据需要占用不同大小的内存空间,类型可以告诉编译器为变量分配多大的内存空间。
2. 数据验证:类型可以帮助编译器验证数据的完整性和正确性。例如,如果一个变量被声明为整数类型,那么它就只能存储整数值,如果我们试图将它赋值为字符串或其他数据类型,编译器就会给出错误提示。
3. 数据处理:不同类型的数据有着不同的处理方式,例如整数和浮点数的运算方式就是不同的。因此类型可以告知编译器对数据进行何种运算或操作。
总之,类型让程序员可以更加准确地控制和处理数据。同时,类型也可以帮助编译器在编译时进行静态类型检查,防止一些错误在运行时才被发现,提高程序的可靠性和稳定性。
为什么又有那么多种数据类型
C语言有这么多不同的数据类型,是为了满足不同的需求,更确切地表示各种不同类型的数据。不同的数据类型在存储数据时占用不同的内存空间,也有不同的精度和范围,因此程序员需要根据具体的情况来选择合适的数据类型。
例如,在需要存储一个整数时,如果使用char类型,虽然它能够存储整数,但是它只能够存储非常小的整数,如果需要存储较大的整数,就需要使用int类型或long类型。同样的道理,如果需要存储小数,就需要使用float类型或double类型,因为它们具有更高的精度。
此外,不同的数据类型在编写程序时也有不同的用途。例如,指针类型用于动态内存管理,结构体类型用于组织复杂的数据,枚举类型用于在程序中定义特定的常量等等。
变量的命名规则
在C语言中,变量的命名必须遵循以下规则:
1. 变量名只能由字母、数字和下划线组成,不能使用其他符号。
2. 变量名必须以字母或下划线开头。
3. 变量名不能使用C语言中的关键字(例如,if、for、while等)。
4. 变量名的长度没有限制,但在实际编程中,建议将变量名控制在20个字符以内,以方便阅读和维护。
5. 变量名区分大小写,因此,变量名abc和ABC是不同的变量。
6. 变量名应该选择有意义的名称,能够清晰地反映变量的含义。
变量的命名规范
1. 使用有意义的变量名:应该使用能够清楚反映变量含义的名称,例如,使用count来表示计数器变量。
2. 使用小写字母:建议使用小写字母来表示变量名。这种命名方式更容易阅读和维护代码。 3. 使用驼峰命名法:对于由多个单词组成的变量名,可以使用驼峰命名法来表示,即第一个单词以小写字母开始,后续单词的首字母大写。例如,可以使用studentName来表示学生姓名。
4. 不要使用缩写和简写:尽量避免使用缩写和简写来表示变量名。这样的命名方式很容易引起歧义,降低代码的可读性。
5. 避免使用数字开头:变量名不能以数字开头,因为在C语言中,数字开头的名称会被解释为常量。
6. 使用下划线作为单词之间的分隔符:在驼峰命名法中,需要使用下划线作为单词之间的分隔符。例如,student_name。
7. 注意命名空间:变量名应该跟变量所属的函数相关,避免命名冲突。
8.使用"g_"或 "s_"前缀:建议在全局变量名前加上"g_"或 "s_"前缀,以便区别于局部变量。其中,"g_"表示全局变量,"s_"表示静态全局变量。
9.所有的宏定义、枚举常量、只读变量全用大写字母命名,用下划线线分割。
定义变量一定要初始化
#include<stdio.h> int main() { int a; printf("%d", a); //vs编译器直接禁止使用未初始化的变量 //error C4700: 使用了未初始化的局部变量“a” return 0; }
如果您声明了一个局部变量但没有初始化它,那么这个变量的初始值将是未定义的,并且其内容可能是任意值。打印未初始化的变量的值是一种不确定行为,因为其内容是不确定的,可能会有垃圾值、0或其他值。
sizeof(int) *p表示什么意思
继上章的sizeof关键字,我们接着来讲解sizeof关键字,先回忆回忆sizeof是干嘛的
#include<stdio.h> int main() { int* p = NULL; //声明一个指向整型变量的指针,赋初值为NULL。 int arr[10]; //声明一个包含10个整型变量的数组。 int* test[3]; //声明一个包含3个指向整型变量的指针数组。 printf("%d\n", sizeof(p));//4 printf("%d\n", sizeof(arr));//40 printf("%d\n", sizeof(test));//12 return 0; }
`sizeof`是C和C++中的一个操作符,用于获取其操作数(变量、类型、表达式等)的字节大小。
那么现在来解释一下sizeof(int) *p表示什么意思。
`sizeof(int)`是一个求整型变量大小的操作符,它返回类型`int`在内存中占据的字节数。通常情况下,一个`int`类型变量占据4个字节(32位系统)或者8个字节(64位系统),具体取决于编译器和操作系统的实现。
`*p`是指针运算符,用来访问指针所指向的内存地址处的值。`p`是一个指向某个整型变量的指针。
因此,`sizeof(int) *p`表示用一个指向整型变量的指针`p`存储一个整型变量的大小。因为一个`int`类型变量通常占据4个字节,所以这条语句等价于`4 *p`。
注意,`sizeof`是一个关键字,而不是函数,不需要用括号将它的参数括起来。在这个例子中,括号会被认为是指向一个函数的指针,而不是求类型大小的操作符。因此,正确的写法应该是`sizeof(int) * p`。
原码、反码和补码的概念
原码(Sign-Magnitude):原码是二进制表示有符号整数的最简单方式,它的表示方法就是使用二进制数,最高位表示符号位,0表示正数,1表示负数。例如,+5的原码为00000101,-5的原码为10000101。原码的优点是简单直观,易于理解,但是存在着符号位和数值位的处理不一致的问题。
反码(One's Complement):反码是在原码的基础上,为了解决符号位和数值位处理不一致的问题而设计的。对于正数,其反码就是其原码本身;对于负数,反码的符号位一定是1,数值部分则取原码的数值部分按位取反(0变成1,1变成0),得到的二进制码就是该负数的反码表示。例如,+5的反码为00000101,-5的反码为11111010。反码的优点是对于数值部分的计算仍然是直接相加,但是符号位仍需要额外判断。
补码(Two's Complement):补码是在反码的基础上,为了解决符号位和数值位处理不一致的问题而产生的。补码表示负数时,先将其转换为其反码,再将反码加1得到补码;补码表示正数时,与原码一样。例如,+5的补码为00000101,-5的补码为11111011。补码的优点在于符号位的处理与数值位的处理是统一的,不需要特殊处理。在补码的表示方式下,负数的补码是它的绝对值的原码按位取反再加1,正数的补码和原码一样。
总的来说,原码、反码和补码都是表示整数的方法,但是它们对于负数的处理方式不同,补码是最常用的表示方法,也是计算机中进行加减运算时的默认方式,因为补码可以实现符号位和数值位的统一处理,同时在计算机中进行加减运算时也非常方便。
计算机中数据计算时,为什么要转为二级制
二进制是一种只包含二个数字(0和1)的进制,这种进制可以用来表示所有数字、文字、图形等。而计算机中的所有操作都是由电子元器件完成的,这些元器件只能表示两种状态(电信号的通/断状态),即0和1,所以在计算机中使用二进制可以更直接地与硬件电路之间进行交互。具体来说,计算机将二进制位串(由一系列0和1组成的序列)转换为数字、文字、图形等,进行处理后再将其转换为二进制位串储存到计算机存储器中,在需要时再将其读取并进行相应的操作,最后再将其转换为人类可读的形式输出。这种转换过程虽然看似繁琐,但是计算机中的各种运算、逻辑判断、图像处理等操作都是以二进制数值形式进行的,因此转换为二进制有助于计算机进行高效的运算和存储。所以任何数据在计算中中,都必须转为二级制。
unsigned和signed关键字
unsigned和signed关键字的理解
在计算机中,整数类型的表示和存储通常是通过二进制补码来完成的。对于有符号整数类型(即signed类型),最高位是符号位,0表示正数,1表示负数。如果要表示-1这个数,需要使用二进制补码来表示,即将1的二进制码取反(变成0),再加1,得到11111111(表示-1的补码),正数的原反补码相同。
而对于无符号整数类型(即unsigned类型),没有符号位,其所有二进制位都表示数值,最小值为0。其原反补码都相同,因此,对于unsigned类型的整数,它只能表示非负整数,而无法表示负数。
因为signed和unsigned类型的表示方式不同,所以它们在使用时需要注意:
1. 范围不同:带符号类型能够表示的整数范围是从负的最大值到正的最大值,而无符号类型只能表示从0到正的最大值。
2. 溢出问题:在进行运算时,如果signed类型的值超过了其范围,会出现溢出现象。而unsigned类型的值超过了其范围,则会进行“回绕”,即从最小值重新开始。
3. 运算方式不同:在进行运算时,signed类型和unsigned类型的运算方式也有所不同。比如,在进行位运算时,signed类型的值会进行符号扩展,而unsigned类型的值则会进行零扩展。
计算二进制的便捷方法 - 2^n
#include<stdio.h> int main() { //计算机内存储的整形必须是补码 int a = 10; //任何数据在计算中中,都必须转为二级制 //符号位(0,1) + 数据位 //有符号正数,原反补码相同 //0000 0000 0000 0000 0000 0000 0000 1010 - 原码、反码、补码 //16进制 //0x00 00 00 0a int b = -20; //16+4 16 = 2^4 4 = 2^2 //2^n次方 二级制1后面就有n个0 //16 = 2^4 10000 //4 = 2^2 00100 // 相加 //因为-20是负数 int - 4字节 - 32位 //最高位是符号位 - 负数 - 1 //1000 0000 0000 0000 0000 0000 0001 0100 - 原码 //1111 1111 1111 1111 1111 1111 1110 1011 - 反码,符号位不变,其他按位取反 //1111 1111 1111 1111 1111 1111 1110 1100 - 补码,反码加1 //16进制 //0xff ff ff ec return 0; }
计算补码的方法
计算补码的方法如下:
1. 对于正数,其原码、反码和补码相同。
2. 对于负数,先求其绝对值的二进制表示的反码(即除符号位外的各位取反),然后再将其反码加1得到其补码。
例如,假设要求-5的补码,步骤如下:
1. 5的二进制表示为0000 0101,因为是正数,所以补码、反码和原码都相同,都是0000 0101。
2. 将其转换为负数,即符号位变为1,得到1000 0101。
3. 除符号位外的各位取反,得到1111 1010,这就是-5的反码。
4. 将反码加1,得到1111 1011,这就是-5的补码。
因此,-5的补码是1111 1011。需要注意的是,在计算机中,通常采用补码表示有符号整数,这样可以避免加减法、逻辑运算等操作的特殊处理。
计算原码的方法
原码是一种二进制数的表示方法,符号位为0表示正数,为1表示负数。计算原码的方法如下:
1. 对于正数,直接将其转换为二进制数即可得到原码。
2. 对于负数,先将其转换成绝对值的二进制数,然后将该二进制数的每个位取反(0变成1,1变成0),最后再将符号位变成1即可得到原码。
3.通过补码求原码
3.1.-20的补码 -> 原码
方法一: 1111 1111 1111 1111 1111 1111 1110 1100 - 补码 1111 1111 1111 1111 1111 1111 1110 1011 - 反码 = 补码 - 1 1000 0000 0000 0000 0000 0000 0001 0100 - 原码 = 反码按位取反,符号位不变
3.2.-20的补码 -> 原码
方法二: 1111 1111 1111 1111 1111 1111 1110 1100 - 原码 1000 0000 0000 0000 0000 0000 0001 0011 - 反码,符号位不变,其他按位取反 1000 0000 0000 0000 0000 0000 0001 0100 - 补码,反码加1
将上面的10和-20的补码转为16进制分别是0x00 00 00 0a和0xff ff ff ec,那我们再来看看它在计算机的内存是怎么存储的。
但是我们发现和我们计算的十六进制有一些区别,计算机的顺序好像是到过来的,这里我们就需要了解计算机存储数据的方式 - 大小端
大小端概念
大小端(Endianness)是用于描述不同类型的计算机中多字节数据的存储方式。简单来说就是指定了大字节和小字节的存储顺序。一个字节通常由8个二进制位组成,而多字节数据是由多个字节组成的。在存储多字节数据时,我们需要确定这些字节在内存中的排列顺序。 具体来说,大端模式(Big Endian)是将最高有效位存放在最低的内存地址,而小端模式(Little Endian)则是将最低有效位存放在最低的内存地址。在大端模式中,字节序列的存储顺序与它们在数值序列中的顺序一致;而在小端模式中,字节序列的存储顺序与它们在数值序列中的顺序相反。 例如,十六进制值为0x12345678的32位整数,在大端模式中的存储顺序为12 34 56 78,而在小端模式中的存储顺序为78 56 34 12。 不同的处理器和操作系统使用的大小端模式可能不同,因此在进行数据交换和传输时,需要注意其大小端模式的差异。
所以我们刚刚求解的十六进制是大端模式,而我们的电脑存储数据的方式是小端模式。
反码在进行+1的操作时候,符号位也是要参与运行的
接下来我们看一下下面的代码是否正确
#include<stdio.h>
int main()
{
unsigned int a = 10;//right
unsigned int b = -10;//?
//编译不报错
return 0;
}
在这个代码中,将-10赋值给了unsigned int类型的变量b。由于unsigned int是无符号整型,它的取值范围是0~4294967295,因此b实际上存储的是4294967286,这是-10的补码在无符号整型范围内的表示。