1
数据类型
- 基本类型:char short int long float double
复合类型:数组 结构体 共用体 - 数据类型就好像一个模子,这个模子实例化出C语言的变量。变量存储在内存中,需要占用一定的内存空间。每种数据类型在不同的机器平台上占用内存是不同的。(一般为32位CPU)可用sizeof运算符计算得出。
有符号数和无符号数
- 对于char int 等整型类型的数,分为有符号数和无符号数,而对于float和double这种浮点数来说,只有有符号数,没有无符号数。
- 变量是存储在内存中的。存储的时候是以二进制方式存储的。对于有符号和无符号数来说,存储方式不同。对于int类型,无符号数:4字节(32位)全部用来存储数的内容;有符号数:32位中最高位用来存符号(0表示正数,1表示负数),剩余31位用来存数据。
- 从绝对数值上来说,无符号数所表示的范围要大一些。
- 对于float和doule这种浮点类型来说,它们在内存中的存储方式和整型不一样。绝对不能随意改变一个变量的存取方式。
空类型(void)
- C语言中的void类型,代表任意类型,而不是空的意思。任意类型的意思是它的类型是未知的,还没有指定。
- 函数的参数列表为void:表示这个函数调用时不需要给它传参数。
- 函数的返回值为void:表示这个函数不会返回一个有意义的返回值。
- void *:是任意类型的指针。(绝对不能随意改变一个变量的存取方式。)存取类型完全有自己负责,编译器不能帮你做类型检查。
细节1
-
一字节为八个二进制位。
-
strlen:strlen 是一个函数,它用来计算指定字符串 str 的长度,但不包括结束字符(即 null 字符)。
-
sizeof:sizeof 是一个单目运算符,而不是一个函数。与函数 strlen 不同,它的参数可以是数组、指针、类型、对象、函数等。功能是获得保证能容纳实现所建立的最大对象的字节大小。
-
字符数组及它的两种初始化
1 #include<stdio.h>
2 int main()
3 {
4 char a[] = "abcde"; // 6
5 char b[] = {'a','b','c','d','e'}; // 5
6 printf("sizeof(a) = %d,sizeof(b) = %d\n",sizeof(a),sizeof(b));
7 return 0;
8 }
结果为:sizeof(a) = 6,sizeof(b) = 5
1,"abcde"实际上有6个字符,分别为'a','b','c','d','e','\0';
2,'\0'这个字符是ASCII码的第一个字符,它的编码值是0;'\0'是C语言中定义的字符串的结尾标志。所以当C语言程序中使用"abcde"这种方式初始化时,编译器会自动在字符'e'后面添加一个'\0'。所以变成了6个字符。
指针
- 指针全称是指针变量,其实质是C语言的一种变量。这种变量比较特殊,通常他的值会被赋值为某个变量的地址值,然后可以使用*p这样的方式去间接访问p所指向的那个变量。
- int *p; 定义指针变量p,在定义时这里的 *含义是告诉编译器p是一个指针变量。
- *p = 123;使用指针的时候,*p代表指针变量p所指向的那个变量。
- 各种不同的指针
指针变量本质是一个变量,指针变量的类型属于指针类型。
1 int *p;// 定义了一个指针类型的变量p,这个p所指向的那个变量是int型。
1 int a;
2 float *p;
3 p = &a;//warning: assignment from incompatible pointer type
各种指针类型和它所指向的变量类型必须匹配,否则结果不可预知。
- 指针与数组的初步结合
数组名:做右值时,数组名表示数组的首元素地址,因此可以直接赋值给指针。
1 int a[5];//a 和 &a[0]都表示数组首元素a[0]的地址,而&a表示数组的首地址。
注意:数组首元素的地址和数组的首地址是不同的。前者是数组元素的地址,后者是数组整体的地址。两个含义不同,但数值上是相同的。
1 int a[];
2 int *p;
3 a = p;
//编译报错,因为数组名是个常量,所以不能赋值,数组名不能做左值。
- 函数传参中使用指针
1 int add(int a,int b)
//实际调用该函数时,实参将自己拷贝一份,并将拷贝传递给形参进行运算,实参自己实际是不参与的。所以,在函数中,是没法改变实参本身的。
1 #include<stdio.h>
2
3 int swap(int &a,int &b)
4 {
5 int t;
6 t = a;
7 a = b;
8 b = t;
9 }
10 int main()
11 {
12 int a = 2,b = 3;
13 swap(a,b);
14 printf("a = %d\n",a);
15 printf("b = %d\n",b);
16 return 0;
17 }
输出: a = 2
b = 3
参数是a,b的地址
1 #include<stdio.h>
2
3 int swap_pointer(int *a,int *b)
4 {
5 int t;
6 t = *a;
7 *a = *b;
8 *b = t;
9 }
10 int main()
11 {
12 int a = 2,b = 3;
13 swap_pointer(&a,&b);
14 printf("a = %d\n",a);
15 printf("b = %d\n",b);
16 return 0;
17 }
输出: a = 3
b = 2
局部变量和全局变量
- 定义的同时没有初始化时,局部变量的值是随机的,而全局变量的值默认是0 。
- 使用范围上,全局变量具有文件作用域(整个文件),而局部变量只有代码块(在{ }中)作用域。
- 生命周期上,全局变量是在程序开始运行前的初始化阶段就诞生,到整个程序结束退出的时候才死亡;而局部变量在进入局部变量所在的代码时诞生,在该代码块退出的时候死亡。
- 分配位置上,全局变量分配在数据段上,而局部变量在栈上。
- 数据段:存的是数,全局变量存在数据段。代码段:存的是代码,一般是只读的。栈(stack):先进后出,局部变量存在栈中。
局部变量
- 被调函数被main函数调用结束,普通的局部变量(auto)的内存就被释放了;**静态局部变量(static)**的内存不释放,和全局变量非常类似。
- register(寄存器)类型的局部变量表现上和普通局部变量一样,被称为是C语言中最快变量。C语言会将register变量放到寄存器中运行(普通的变量是在内存中),所以register变量访问速度会很快。但是它是有限制的,因为寄存器数目是有限的,其次register变量在数据类型上有限制,例如不能定义double类型的register变量。一般只在内核或者启动代码中,需要反复使用同一个变量才会使用register变量。
全局变量
- 全局变量的定义和初始化是在main函数运行之前发生的。
- 普通全局变量可以在各个文件中使用,可以在项目内别的.c文件中被看到,所以要确保变量名不能重名。静态全局变量就是解决重名问题的。它告诉编译器这个变量只在当前本文件内使用,这样就不用担心重名问题。
跨文件的变量引用
- 用关键字extern声明一个跨文件变量
常量
- #define N 20:
- const:const和指针结合,有四种形式:
const int *p:p是一个指针,指针指向一个int型数据。p所指向的数据是个常量。
int const *p:p是一个指针,指针指向一个int型数据。p所指向的数据是个常量。
int *const p:p是一个指针,指针指向一个int型数据。p本身是常量,p所指向的数据是个变量。
const int *const p:p是一个指针,指针指向一个int型数据。p本身是常量,p所指向的数据是个常量。
头文件的引入
- #include<>:用来包含系统自带的头文件。
- #include“ ”:用来包含当前目录中的头文件。
- 防止重复包含头文件
#ifndef _A_H_
#define _A_H_
#endif