系列文章目录
目录
1. Hello word
#include <stdio.h>
int main() //main函数是程序的入口,有且仅有一个
{
printf("hello world\n");
return 0;
}
2. 数据类型
short 短整型(2)
int 整形 (4)
long 长整型(4)
long long 更长的整形(8)
float 单精度浮点数(4)
double 双精度浮点数(8)
3. 变量、常量
3.1 定义变量的方法
int age = 10;
float weight = 5.5f;
char ch = 'a';
3.2 变量的命名
1. 只能由字母(包括大写和小写)、数字和下划线( _ )组成。
2. 不能以数字开头。
3. 长度不能超过63个字符。
4. 变量名中区分大小写的。
5. 变量名不能使用关键字。
3.3 变量的分类
#include <stdio.h>
int year = 2019;//全局变量
int main()
{
int now = 2018;//局部变量
printf("now = %d\n", now);
printf("year = %d\n", year);
return 0;
}
3.4 变量的作用域和生命周期
- 作用域
- 生命周期
3.5 常量
- 常量分为以下以下几种:
//例子上的 test 为 const 修饰的常变量, const修饰的常变量在C语言中只是在语法层面限制了变量 test 不能直接被改变
//但是 test 本质上还是一个变量的,所以叫常变量。
#include <stdio.h>
enum Gender // 这是一个枚举类型定义。枚举类型Gender有三个成员:MALE、FEMALE和SECRET。
{
MALE,
FEMALE,
SECRET
};
//枚举常量默认从0开始编号,即MALE为0,FEMALE为1,SECRET为2。
int main()
{
//这些字面常量在这里没有实际作用,仅作为展示。
5;//字面常量
5.5;//字面常量
//这里定义了一个const修饰的常变量test,其值被初始化为123。
//由于它被const修饰,尝试修改test的值(如test = 5.14;)将导致编译错误,因为const变量的值不可修改。
const float test = 123; //这里的pai是const修饰的常变量
test = 5.14;//不能直接修改常变量的值,否则会报错
//#define的标识符常量是在预处理阶段由预处理器处理的,它是在编译阶段被替换的,不占内存。
#define T 100
printf("t = %d\n", T);
//枚举常量演示
printf("%d\n", MALE);
printf("%d\n", FEMALE);
printf("%d\n", SECRET);
//打印前面定义的枚举常量的值。根据枚举的默认行为,输出将依次是0, 1, 和2。
return 0;
}
4. 字符串和转义字符
4.1 字符串
"hello world.\n"
int main()
{
char arr1[] = "bit";
char arr2[] = {'b', 'i', 't'};
char arr3[] = {'b', 'i', 't', '\0'};
printf("%s\n", arr1);
printf("%s\n", arr2);
printf("%s\n", arr3);
return 0;
}
从输出结果可以看出\0 结束标志的作用。
4.2 转义字符
'\''
表示单引号字符。
\\
。
#include <stdio.h>
int main()
{
printf("%c\n", '\''); //在屏幕上打印一个单引号
printf("%s\n", "\""); //在屏幕上打印一个双引号
printf("%d\n", strlen("abcdef"));
// \62被解析成一个转义字符
printf("%d\n", strlen("c:\test\628\test.c")); //在屏幕上打印一个目录
return 0;
}
5. 选择语句
#include <stdio.h>
int main()
{
int select = 0;
// 提示用户输入选择,1代表学习C语言,0代表学习Python
printf("学习C还是python(选择1 or 0):>");
// 使用scanf函数读取用户输入的整数,并将其存储在select变量中
scanf("%d", &select);
if(select == 1)
{
printf("学习C语言\n");
}
else
{
printf("学习Python\n");
}
return 0;
}
6. 循环语句
C语言一共有三种循环:
//while循环的实例
#include <stdio.h>
int main()
{
printf("循环开始\n");
int line = 0; // 定义整型变量line并初始化为0,用于控制循环的次数
while(line<=10) // // while循环的条件是line小于或等于10
{
line++; // 在循环体的开始先将line的值加1
printf("正在循环\n");
}
if(line>10) // 当line的值大于10时,while循环结束
printf("循环结束\n");
return 0;
}
7. 函数
函数是一组组织在一起以执行特定任务的语句块。函数可以执行计算、执行操作、处理数据等,并且可以重复使用。
首先看下面这段代码(常规代码实现加法)
#include <stdio.h>
int main()
{
int num1 = 0;
int num2 = 0;
int sum = 0;
printf("输入两个数值:>");
scanf("%d %d", &num1, &num2);
sum = num1 + num2;
printf("sum = %d\n", sum);
return 0;
}
下面改成通过加法函数的方式来实现。
#include <stdio.h>
int Add(int x, int y) // 定义一个函数Add,接收两个参数x和y
{
int z = x+y; // 在函数内部计算x和y的和,并将结果存储在变量z中
return z; // 返回计算得到的和
}
int main()
{
int num1 = 0;
int num2 = 0;
int sum = 0;
printf("输入两个数值:>");
scanf("%d %d", &num1, &num2);
sum = Add(num1, num2); // 调用函数Add,传入num1和num2作为参数,并将返回值赋给sum
printf("sum = %d\n", sum);
return 0;
}
8. 数组
8.1 数组定义
int arrays[10] = {1,2,3,4,5,6,7,8,9,10}; //定义一个整形数组,最多放10个元素
8.2 数组的下标
int arrays[10] = {0}; //如果数组10个元素,下标的范围是0-9
这里 arrays
是数组的名称,[10]
指定了数组的大小,意味着它可以包含10个整数元素。数组被初始化为 {0}
,这表示数组中的所有元素都被初始化为0。
数组的每个元素都可以通过其下标来访问。数组 arrays
的下标和对应元素的值如下所示:
arrays [0]
的值是0
(第一个元素)arrays [1]
的值是0
(第二个元素)arrays [2]
的值是0
(第三个元素)- ...
arrays [9]
的值是0
(第十个元素)
8.3 数组的使用
#include <stdio.h>
int main()
{
int i = 0;
// 声明并初始化一个名为arrays的整数数组,包含10个整数元素,元素值从1到10
int arrays[10] = {1,2,3,4,5,6,7,8,9,10};
// for循环开始,初始条件为i=0,循环继续的条件是i<10,每次循环结束后i的值增加1
for(i=0; i<10; i++)
{
printf("%d", arrays[i]); // 使用printf函数打印当前i所指向的数组元素的值
}
printf("\n");
return 0;
}
9. 操作符
+
:加法操作符,用于计算两个数的和。-
:减法操作符,用于计算两个数的差。*
:乘法操作符,用于计算两个数的积。/
:除法操作符,用于计算两个数的商。%
:求余操作符(模运算符),用于计算两个数相除的余数。
>>
:右移操作符,将数字的位向右移动指定的位数,高位丢弃,低位通常补0。<<
:左移操作符,将数字的位向左移动指定的位数,低位补0。
&
:按位与操作符,对两个数的二进制表示进行逐位与操作。^
:按位异或操作符,对两个数的二进制表示进行逐位异或操作。|
:按位或操作符,对两个数的二进制表示进行逐位或操作。
=
:基本赋值操作符,将右侧表达式的值赋给左侧的变量。+=
:加法赋值操作符,将右侧表达式的值加上左侧变量的值,然后将结果赋给左侧变量。-=
:减法赋值操作符,从左侧变量的值中减去右侧表达式的值,然后将结果赋给左侧变量。*=
:乘法赋值操作符,将左侧变量的值与右侧表达式的值相乘,然后将结果赋给左侧变量。/=
:除法赋值操作符,将左侧变量的值除以右侧表达式的值,然后将结果赋给左侧变量。&=
:按位与赋值操作符,对左侧变量与右侧表达式进行按位与操作,然后将结果赋给左侧变量。^=
:按位异或赋值操作符,对左侧变量与右侧表达式进行按位异或操作,然后将结果赋给左侧变量。|=
:按位或赋值操作符,对左侧变量与右侧表达式进行按位或操作,然后将结果赋给左侧变量。>>=
:右移赋值操作符,将左侧变量右移右侧表达式指定的位数,然后将结果赋给左侧变量。<<=
:左移赋值操作符,将左侧变量左移右侧表达式指定的位数,然后将结果赋给左侧变量。
!
:逻辑非操作符,用于取反布尔表达式的真值。如果操作数为真(非0),结果为假(0);如果操作数为假(0),结果为真(非0)。-
:一元负号,用于返回操作数的负值。+
:一元正号,通常省略不写,表示操作数的正值。&
:取地址操作符,返回变量的内存地址。sizeof
:返回操作数的类型长度,单位是字节。~
:按位取反操作符,对整数的二进制表示进行按位取反。--
:递减操作符,可以作为前缀(先减少,再返回值)或后缀(先返回值,再减少)。++
:递增操作符,同样可以作为前缀或后缀。*
:间接访问操作符或解引用操作符,用于访问指针指向的变量。(类型)
:强制类型转换,用于将表达式的类型转换为括号中指定的类型。
>
:大于操作符,如果左侧操作数大于右侧操作数,则返回真(非0)。>=
:大于或等于操作符,如果左侧操作数大于或等于右侧操作数,则返回真(非0)。<
:小于操作符,如果左侧操作数小于右侧操作数,则返回真(非0)。<=
:小于或等于操作符,如果左侧操作数小于或等于右侧操作数,则返回真(非0)。!=
:不等于操作符,如果两个操作数不相等,则返回真(非0)。==
:等于操作符,如果两个操作数相等,则返回真(非0)。
&&
:逻辑与操作符,当所有操作数都为真时,结果为真;否则为假。||
:逻辑或操作符,如果任一操作数为真,则结果为真;如果所有操作数都为假,结果为假。
- exp1 ? exp2 : exp3 三元条件操作符,如果表达式exp1 为真(非0),则返回exp2的值,否则返回exp3的值。
- exp1, exp2, exp3, …expN 逗号操作符用于链接表达式,从左到右顺序求值,并返回最后一个表达式的值。
[]
:下标操作符,用于访问数组中的元素。()
:函数调用操作符,用于调用函数。.
:直接成员访问操作符,用于访问结构体或联合体的成员。->
:间接成员访问操作符,用于通过指向结构体或联合体的指针来访问其成员。
10. 关键字
C语言关键字是预先定义的保留字,它们具有特定的意义,用来表示数据类型、流程控制语句和其他编程结构。关键字不能用作变量名、函数名或其他标识符名称。
auto break case char const continue default do double else enum
extern float for goto if int long register return short signed
sizeof static struct switch typedef union unsigned void volatile while
auto
:用于声明自动变量,其存储类别指定为自动存储期。break
:用于立即退出最近的循环或switch
语句。case
:与switch
语句结合使用,用于指定一个条件分支。char
:用于声明字符型变量或数组。const
:用于声明一个常量,表示变量的值在程序运行时不会被修改。continue
:使控制流跳过当前循环的剩余部分,立即进入下一次循环的迭代。default
:与switch
语句结合使用,定义一个默认分支,当没有匹配的case
时执行。do
:与while
一起使用,创建一个循环结构,至少执行一次循环体。double
:用于声明双精度浮点型变量或数组。else
:与if
语句结合使用,用于创建条件分支。enum
:定义一个枚举类型,用于声明一组命名的整型常量。extern
:声明一个变量或函数是在别处定义的,即指示编译器寻找另一个文件中的定义。float
:用于声明单精度浮点型变量或数组。for
:创建一个循环结构,可以指定初始化、条件和迭代表达式。goto
:用于无条件地跳转到程序中标记的位置。if
:用于创建基于条件的分支。int
:用于声明整型变量或数组。long
:用于声明长整型变量或数组,也可以用来声明长双精度类型long double
。register
:提示编译器尝试使用寄存器来存储变量,以便快速访问。return
:从函数返回一个值并结束函数的执行。short
:用于声明短整型变量或数组。signed
:与整型数据类型结合使用,指明变量可以存储负数。sizeof
:计算类型或变量所占内存大小的运算符。static
:声明静态变量或函数,使其在文件内保持局部作用域。struct
:定义一个结构体类型,用于将不同类型的数据项组合成一个单元。switch
:根据一个整型表达式的值选择多个代码块之一来执行。typedef
:为一个已存在的类型创建一个新的名称(别名)。union
:定义一个联合体,其成员共享同一块内存。unsigned
:与整型数据类型结合使用,指明变量只能存储非负数。void
:表示无类型,用于指定没有返回值的函数或未指定类型的指针。volatile
:指示编译器一个变量的值可能以编译器未预料的方式改变。while
:创建一个循环结构,在满足指定条件的情况下反复执行循环体。
11. 指针
11.1 内存
#include <stdio.h>
int main()
{
int num = 10; // 声明一个类型为int的变量num,并初始化为10。
# // 取出变量num的地址。
// 使用printf函数打印num的地址。%p格式说明符用于打印指针或地址。
// 在打印时,地址通常以十六进制形式表示。
printf("%p\n", &num);
return 0;
}
11.2 指针和指针变量
在C语言中,指针是一个非常强大的特性,因为它允许程序直接访问和操作内存。指针本身是一个变量,但它存储的不是普通的数据,而是另一个变量的地址。
#include <stdio.h>
int main()
{
int num = 10; // 定义一个整型变量num,并初始化为10。
int *p = # // 定义一个整型指针变量p,并初始化为num的地址。
*p = 20; // 通过指针p修改num的值。现在num的值变成了20。
return 0;
}
#include <stdio.h>
int main()
{
char word = 'w'; // 声明一个类型为char的变量word,并初始化为字符'w'
char* pc = &word; // 声明一个类型为char*的指针变量pc,并初始化为变量word的地址
*pc = 'q'; // 解引用指针pc,即访问pc指向的地址(即word的地址)并将其值修改为'q'
printf("%c\n", word); // 这里会打印出'q'
return 0;
}
这里可能会感觉程序本来可以直接修改num的值,现在反而多用了一个指针来修改,好像更复杂了。然而,指针的力量在于它们提供了访问和操作内存的灵活性,这在以下几个场景中非常有用:
-
函数参数传递:如果你想在函数中修改变量的值,并且让这些修改反映到调用者那里,你需要使用指针。在C语言中,函数参数是通过值传递的,这意味着函数接收的是参数值的副本。通过传递指向实际变量的指针,函数可以直接修改变量的值。
-
动态内存分配:C语言使用指针来动态分配和管理内存。通过指针,你可以在运行时分配内存块,其大小并不需要在编译时确定,这为创建复杂的数据结构如链表、树、图等提供了可能。
-
数组和字符串操作:指针在处理数组和字符串时非常有用。字符串在C中通过字符数组实现,指针可以方便地遍历和操作这些数组。
-
效率:对于大型数据结构,如大数组或结构体,使用指针传递它们的地址比复制整个数据结构要高效得多,因为只需要复制地址值而不是结构的每个部分。
-
接口和抽象:在一些情况下,指针用于创建对数据的抽象表示,比如文件句柄等。
-
底层操作:指针使得程序能够与硬件直接交互,这在嵌入式系统和操作系统的开发中尤为重要。
11.3 指针变量的大小
- 在32位系统中,所有类型的指针的大小通常是4个字节(32位)。
- 在64位系统中,所有类型的指针的大小通常是8个字节(64位)。
12. 结构体
结构体是一种用户自定义的数据类型,它允许存储不同数据类型的数据项。
struct people
{
char name[20]; // 一个20个字符的数组,用于存储姓名
int age; // 一个 int 类型的变量,用于存储年龄
char sex[5]; // 一个5个字符的数组,用于存储性别
};
结构体初始化和成员访问:
// 创建并初始化一个名为 s 的 people 结构体的实例,初始化时,每个值依次赋给结构体的成员
struct people s = {"某某某", 20, "男"};
// 使用结构体成员访问和打印
printf("name = %s age = %d sex = %s", s.name, s.age, s.sex);
指针访问结构体:
// 指针变量
struct people *ps = &s; //声明了一个指向 people 结构体的指针 ps,并将它初始化为 s 的地址
// 通过使用箭头操作符 ->,可以通过指针访问结构体的成员。
printf("name = %s age = %d sex = %s id = %s\n", ps->name, ps->age, ps->sex, ps->id);
这两段代码示例展示了如何在C语言中使用结构体(struct
),包括如何初始化结构体变量,如何直接访问结构体的成员,以及如何通过指针访问结构体的成员。