- 一些基础的知识,以及对其的理解与疑问
- 不积跬步,无以至千里;不积小河无以成江海!
最基本的数据类型,char,int, long,float,double.
这里需要注意的是,这几个数据类型占据内存的大小,使用**sizeof()**函数,得到数据类型大小,如下所示,
int main() {
printf("%d\n", sizeof(int)); // 4
printf("%d\n", sizeof(char)); // 1
printf("%d\n", sizeof(short)); // 2
return 0;
}
还需要明白字节和比特之间的换算关系,1字节(byte) = 8bit, 而int类型占据4个字节,也即是32bit,其他数据类型相同。这说明,存储不同的数字使用不同的数据类型,这样可以节省内存空间。此外, 存储在计算机中数字是使用二进制来存储的,所以,int 可以存储很多数字,有 2 32 2^{32} 232种。
00000000 00000000 00000000 00101010
上述二进制代码代表数字42.同理,它还可以表示一个很大的数字,基本我们生活中基本都够用了。
但是,一个数字,在内存中是如何存储的呢? 比如,我们定义了
int num = 42;
它是如何在内存中存储或映射的?和地址之间又有什么关系?
先来明确一下地址的定义吧。地址是
内存地址用于访问和定位数据、变量、对象或指令在计算机的物理内存中的位置,重点是提供一个位置,就像是房间号一样。
它是一个数值,表示存储单元的位置,这个存储单元可以是一个数、一个字节等等。它通常是16进制来表示。
上面的42 的二进制表示只是数字在内存中的存储形式,而不是地址,地址是16进制来表示这个二进制数字的房间号的!
取地址符号是经典的 &,用这个符号可以将地址取出来,后面指针也会用到这个取地址符。
int x = 42;
printf("%p\n", &x); // 0000008BFCDBF8A4
数字42的地址。这里注意,输入变量需要加 &, 因为计算机需要知道你输入的符号存储到哪一个地址中!要取出来一个地址给你存进去。
其实我还有一个问题,即int 和 short我一般什么时候使用? 这涉及到定义存储的数字的大小了,如果int存储的数字范围大,当要存储的数字可能很大时,那么就使用int,而short由于只占据2个字节,16个bit,存储的数字范围小很多,在-32,768 - 32,767之间的数字,都可以使用short来存储!
- 变量和常量
这里引入一个相当于python中的input函数,scanf(“%d”, int), 接收一个输入整数!
一些常量的定义
- const 修饰的常量
简单来说,被const 修饰的常量,之后就不可以更改了!举例来说,
const short x = 42;
//int x = 33; 不能修改了哦
printf("%d", x);
这个适用于一些定死的常量,在后面的某些操作中可能会出现改变这个常量值的函数或操作,那么我们不希望改变, 这里使用const 最合适了。
- #define定义的常量
我觉得最有用的就是使用这个可以提高代码的可读性,当然还有它可以在其他c文件中使用,所以用起来简洁方便.
如果您有多个源文件,您可以将常用的常量定义在一个头文件中,并在需要的文件中包含该头文件,以便在不同的文件中共享常量
-
转义字符
一些常见的转义字符 \n \b \t … \xdd \ddd, 一般来说需要注意这种 \223 \w33 ,这都是转义字符! -
数组
创建一个长度为11的数组,可以存储11个元素。
int arr[11] = { 1,2,3 };
printf("%d",arr[0]);
return 0;
- 指针
指针该怎么理解呢? 要先从内存入手!
每个内存单元的大小是1个字节,也就是8bit;前面我们提到,int类型是4个字节,即32bit,也即是存储一个int整数,需要占用4个内存单元,而每一个内存单元都是一个地址,都有一个地址编号(16进制)。那么我们存储的变量(int 42),也会有地址编号,虽然它占据四个内存单元,但是我认为它们的地址可以唯一表示,可以理解为4个地址重新编号,然后生成一个新的地址!
以上理解有些问题, 取地址符**&**只会取出int 42 中的第一个地址,不是全部地址,也不是重新生成的地址,一般来说,就使用这第一个地址来代表这个数值的在内存中的地址了。
所以,如果您取一个 int 变量的地址,只会得到一个地址,而不会得到四个地址。这个地址可以用来访问整个 int 变量的四个字节!
然后,是对指针最简单直接的理解,
int x = 42;
int* pt = &x;
这表明,指针变量pt存储了x 的地址 ,而这个地址,指向了x的第一个字节(第一个内存单元的地址),注意,一定要明白,int* pt 存储的是x的地址!!举例,
int x = 42;
int* ptr = &x;
printf("%p\n", ptr); // 0000007AA2D3FA64
*ptr = 33;
printf("%d\n", x); // 33
这里,ptr打印出来是x最低有效字节的地址,而后面我们使用解引用 操作符(间接访问操作符)来修改指向x地址存储的变量的值,可以看到x的真实值也随之修改了。
*ptr中的 * 作用是通过地址访问内存中的数据,相当于我根据房间号码进入了房间,可以做很多事情了!
对于指针变量的大小,它取决于地址的大小,有32bit 和 64bit。即4 和 8个字节。在32位平台指针变量大小和int类型大小一样,是4个字节;而在64位平台,则是8个byte!
- 结构体
定义一个简单的结构体
struct Stu
{
char name[20];
int price;
char sex[5];
char id[22];
};
这个结构体里面预定义了一些学生的基本信息,需要到后面的函数中进行调用。
struct Stu* ps = &s; // 定义指针变量来存储s的地址,然后一一使用-> 来进行访问。
printf("name %s", ps -> name);
2023年10月7日22:11:46 今天先这样,明天总结循环语句。
2023年10月8日19:34:41 update…
- 循环语句
首先,最基本的if判断语句, 用的应该也是最多的,在Python 中,有
if a>b: print("something") else: print("something")
而C语言中,有
short age = 10;
if (age >= 15)
printf("hahah");
else
printf("hehe");
这是最简单的一种,还有,
if (age >= 15)
{
printf("hahah");
}
else if (age < 15){
printf("hehe");
}
else
{
printf("this is a test");
}
总结来说,最好给if后面加上结构块,这样代码逻辑更加清晰!
此外, 这里还有一个坑,那就是if else的对齐,else会和没配对的最近if对齐,即使你的缩进写到定格,那也是和上一个if对齐的。
int a = 0;
int b = 2;
if (a == 1)
if (b == 2)
printf("hehe\n");
else // 这个else实际上根本不会进入;缩进一定要规范
printf("haha\n");
这里,按照逻辑,无法满足a==1,那么会走else,输出haha,但是,实际上,并不会有任何的输出,这是因为else会自动和上面最近的if配对,所以无法输出任何东西,解决方法就是加上结构体括号{},
if (a == 1)
{
if (b == 2)
printf("hehe\n");
}
else // 这个else实际上根本不会进入;缩进一定要规范
printf("haha\n");
加上结构体后,表明,第一个if后面是一整块结构体,else就和第一个if配对了,所以写代码,要有随手关门,加上{}的习惯。
switch语句
这个需要注意一点,和上面加上{}一样, 这里需要在每一个case后面都要加上break;
int n = 1;
int m = 2;
switch (n)
{
case 1:
m++;
case 2:
n++;
case 3:
{
switch (n)
{
case 1:
n++; // case 1 不执行,因为 n是判断变量, 此时n=2!
case 2:
m++; n++; break;
}
} // case 3 没有break!!所以还会走case 4
case 4:
m++; break;
default: printf("Error!");
}
在上述代码中,需要注意两点,第一,case 后面接的是整形变量,且,如果case后面的执行语句没有加上break,那么程序会自动往下走,最后结果m=5,n=3;