前言:
大家好,我是hmm.一名大一在校生,在c/c++/java/javase等等方面有着非常浓厚的兴趣,也喜欢分享一些自己学习的心得和把自己所学的分享给大家,喜欢的可以关注收藏!
C生万物,编程之本,长远的IT职业发展的首选,C语言是母体语言,是人机交互接近底层的桥梁,学会C/C++,相当于掌握核心技术,IT行业,一般每十年就有一次变革。 40年间,在TIOBE排行榜中,C/C++位置长期占据前三,没有丝毫撼动,可谓经典永不过时!
很喜欢这样一句话,种子种下的时间最好是在十年前,其次就是现在!
别再给自己灌输毒鸡汤了,什么来不及,就要你此刻觉悟,一切就还都来得及
必须学好:
语言、算法和数据结构、系统调用(操作系统)和计算机网络。
选择一门好的语言,深入学习,完成所有的课后作业,多刷题巩固
课堂以听为主,课下多练习,多刷题
认真听讲+课后练习+主动学习
明确学校所学的知识并不能达到就业基础,必须深入学习,互联网从来不缺知识,缺少的是你去探索的心❤
本章目标
基本了解C语言的基础知识,对c有一个大概的认识
C语言是一门面向过程的、抽象化的通用程序设计语言,广泛应用于底层开发。C语言能以简易的方式编译、处理低级存储器。C语言是仅产生少量的机器语言以及不需要任何运行环境支持便能运行的高效率程序设计语言。尽管C语言提供了许多低级处理的功能,但仍然保持着跨平台的特性,以一个标准规格写出的C语言程序可在包括类似嵌入式处理器以及超级计算机等作业平台的许多计算机平台上进行编译。
简介 :C语言是一门面向过程的计算机编程语言,与C++、C#、Java等面向对象编程语言有所不同。C语言的设计目标是提供一种能以简易的方式编译、处理低级存储器、仅产生少量的机器码以及不需要任何运行环境支持便能运行的编程语言。C语言描述问题比汇编语言迅速、工作量小、可读性好、易于调试、修改和移植,而代码质量与汇编语言相当。C语言一般只比汇编语言代码生成的目标程序效率低10%-20%。因此,C语言可以编写系统软件。
当前阶段,在编程领域中,C语言的运用非常之多,它兼顾了高级语言和汇编语言的优点,相较于其它编程语言具有较大优势。计算机系统设计以及应用程序编写是C语言应用的两大领域。同时,C语言的普适较强,在许多计算机操作系统中都能够得到适用,且效率显著。
C语言拥有经过了漫长发展历史的完整的理论体系,在编程语言中具有举足轻重的地位。
// 包含一个叫stdio.h的文件
//std-标准 standard input output
#include"stdio.h"
int main()//主函数-程序的入口-main函数有且只有一个
{
//这里完成任务
// 在屏幕输出helloworld
// 函数-print(打印) function- printf-打印函数
//printf("helloworld\n");
//库函数-C语言本身提供我们使用的函数
//#include
return 0;
}
/*
int 是整型的意思
main前面的int 表示main函数调用返回一个整型值
int main()
{
return 0; //返回0
}
void main() 写法已将过时
*/
char ----------字符数据类型
short ----------短整型
int---------------整型
long---------------长整型
long long — - - - – -更长的整型
float - – -- – -- – -单精度浮点数
double – -- – — -双精度浮点数
代码练习:
int main()
{
//%d-打印整型
//%c--打印字符
//%f--打印浮点数--小数
//%p--以地址的形式打印
//%x--打印16进制数据
//....
char ch = 'A';
//char-字符类型
// int --整型
// long -- 长整型
long num = 100;
printf("%d", num);
float f = 5.0;
printf("%f", f);
//short int --短整型
printf("%c\n", ch); //%c--打印字符格式的数据
int age = 20;
printf("%d", age); //%d--打印整型十进制数据
double b = 3.14;
printf("%lf\n", b);//打印双精度浮点型
return 0;
}
生活中的有些值是不变的(比如:身份证,性别,姓名等等)
有些值是改变的(如:年龄,体重,身高…)
不变的值,C语言中用常量的概念来表示,变得值C语言中用变量来表示
int age = 20;
float weight = 90.5f;
char ch = 'w';
#include"stdio.h"
int a = 100;//全局变量
int main()
{
//局部变量和全局变量的名字建议不要相同-易产生bug
//当局部变量和全局变量的名字相同时,局部变量优先
int a = 10;//局部变量
printf("%d\n", a);
return 0;
}
总结:
局部变量可与全局变量同名当局部变量量和全局变量同名时局部变量优先使用
计算两个数的和:
int main()
{
//计算两个数的和
int num1 = 0;
int num2 = 0;
//输入数据-使用输入函数scanf
scanf_s("%d%d", &num1, &num2);//取地址符&
//C语言语法规定先定义再使用
int sum = num1 + num2;
printf("sum=%d\n", sum);
return 0;
}
—·
变量的作用域和生命周期
作用域
作用域(scope),程序设计理念,通常说,一段代码所用到的名字并不总是有效的/可用的
而限制这个名字的可用性的代码范围就是作用域
1.局部变量的作用域是变量所在的范围
2.全局变量的作用域是整个工程
生命周期
变量的生命周期指的是变量的创建到变量的销毁之间的一个时段
C语言中的常量和变量的定义的形式有所差异。
C语言中的常量分为以下几种:
#include"stdio.h"
//#define定义的标识符常量
#define MAX 10
enum Sex
{
MALE,
FEMALE,
SECRET,
};
int main()
//枚举常量
//枚举--一一列举
//例:性别,星期...
//枚举关键字: enum
//enum Sex s = MALE;
{
enum Sex s = MALE;
//const--常变量
const int n = 10;//n是变量但又有常属性,所以我们的n常变量
int arr[n] = { 0 };
//consout--修饰的常变量
//int num = 8;
const int num = 8;
printf("%d\n", num);
num = 10;
printf("%d\n", num);
return 0;
}
”hello bit.\n"
这种由双引号(Double Quote)引起来的一串字符称字符串字面值(String Literal),或者简称字符串。
注: 字符串的结束标志是一个\o的转义字符,在计算字符长度的时候\o是结束的标志,不算做字符串的内容
//int float
//char
//字符串类型
int main()
{
char arr1[] = "abc";//数组
char arr2[] = { 'a','b','c' };
printf("%s\n", arr1);
printf("%s\n", arr2);
return 0;
}
int main()
{
char arr1[] = "abc";
char arr2[] = { 'a','b','c' };
printf("%d\n", strlen(arr1));//strlen---string length-计算数组长度
printf("%d\n", strlen(arr2));
//输出:3 arr2->随机值(直到遇到'\0'字符串结束)
return 0;
}
数据在计算机上储存的时候,储存的是二进制
为了存储方便,引荐ASCII编码
ASCII编码表
转变原来的意思
转义字符 | 释义 |
---|---|
\ ? | 在书写连续多个问号时使用,防止他们被解析成三个字母符 |
\ ’ | 用于表示字符常量 ’ |
\ " | 用来表示字符串内部的双引号 |
\ \ | 用来表示一个反斜杠,防止他被解释成一个转义序列字符 |
\a | 警告字符,蜂鸣 |
\b | 退格符 |
\f | 进纸符 |
\n | 换行 |
\r | 回车 |
\t | 水平制表符 |
\v | 垂直制表符 |
\ddd | ddd表示1-3个八进制的数字。如:\130X |
\xdd | dd表示2个十六进制数字。如:\x30 0 |
C语言风格注释/* */
缺陷:不能嵌套注释
C++风格注释//
可以注释一行也可以注释多行
int Add(int x, int y)
{
int z = x + y;
return z;
}
int main()
{
int a=10, b=20;
int sum=0;
sum = Add(a,b);
printf("sum=%d\n", sum);
return 0;
}
函数的特点就是简化代码,代码复用
C语言中数组的定义:一组相同类型的元素的集合
int arr[10] = {1,2,3,4,5,6,7,8,9,10};//定义一个整形数组最多存放十个元素
数组下标1对应下标0依次往后走
通过下表来使用
+ - * / %
移位操作符(移(二进制)位操作符)
>> (右移) <<()左移)
位操作符
&(按位与) ^ |(按位或)
赋值操作符
= += -= *= /= &= ^= |= >>= <<=
符号 | 解释 |
---|---|
! | 逻辑反操作 |
- | 负值 |
+ | 正值 |
& | 取地址 |
sizeof | 操作数的类型长度(以字节为单位) |
~ | 对一个数的二进制按位取反 |
– | 前置、后置– |
++ | qianzhi、后置++ |
* | 间接访问位操作符 |
(类型) | 强制类型转换 |
int main()
{
int a = 11;
//sizeof计算的是变量/类型所占空间的大小,单位是字节
printf("%d\n", sizeof(a));
printf("%d\n", sizeof a);
printf("%d\n", sizeof(int));
return 0;
}
真—非0
假—0
&&—逻辑与
||—逻辑非
exp1 ? exp2 : exp3
逗号表达式
exp1, ? exp 2 ,? exp3,…expN
下标引用,函数调用和结构成员
[ ] () . ->
关键字 | 说明 |
---|---|
auto | 声明自动变量 |
short | 声明短整型变量或函数 |
int | 声明整型变量或函数 |
long | 声明长整型变量或函数 |
float | 声明浮点型变量或函数 |
doubl | 声明双精度变量或函数 |
char | 声明字符型变量或函数 |
struct | 声明结构体变量或函数 |
union | 声明共用数据类型 |
enum | 声明枚举类型 |
typedef | 用以给数据类型取别名 |
const | 声明只读变量 |
unsigned | 声明无符号类型变量或函数 |
signed | 声明有符号类型变量或函数 |
extern | 声明变量是在其他文件正声明 |
register | 声明寄存器变量 |
static | 声明静态变量 |
volatile | 说明变量在程序执行中可被隐含地改变 |
void | 声明函数无返回值或无参数,声明无类型指针 |
if | 条件语句 |
else | 条件语句否定分支(与 if 连用) |
switch | 用于开关语句 |
case | 开关语句分支 |
for | 一种循环语句 |
do | 循环语句的循环体 |
while | 循环语句的循环条件 |
goto | 无条件跳转语句 |
continue | 结束当前循环,开始下一轮循环 |
break | 跳出当前循环 |
default | 开关语句中的“其他”分支 |
sizeof | 计算数据类型长度 |
return | 子程序返回语句(可以带参数,也可不带参数)循环条件 |
关键字static
在C语言中:
static是用来修饰变量和函数的
- 修饰j局部变量-静态局部变量
- 修饰全局变量-讲台全局变量
- 修饰函数–静态函数
改变了变量的作用域—让静态的全局变量只能在自己所在的源文件内部使用,除了源文件就无法使用,static修饰函数
//define 定义标识符常量
#define MAX 100
//define 定义宏
#define ADD(x,y)((x)+(y))
# include"stdio.h"
int main()
{
return 0;
}
指针是程序数据在内存中的地址,而指针变量是用来保存这些地址的变量。
由于内存中的每一个字节都有一个唯一的编号,因此,在程序中使用的变量,常量,甚至数函数等数据,当他们被载入到内存中后,都有自己唯一的一个编号,这个编号就是这个数据的地址。指针就是这样形成的。
#include
int main(void)
{
char ch = 'a';
int num = 97;
printf("ch 的地址:%p
",&ch); //ch 的地址:0028FF47
printf("num的地址:%p
",&num); //num的地址:0028FF40
return 0;
}
1、内存的数据
内存的数据就是变量的值对应的二进制,一切都是二进制。97的二进制是 : 00000000 00000000 00000000 0110000 , 但使用的小端模式存储时,低位数据存放在低地址,所以图中画的时候是倒过来的。
2、内存数据的类型
内存的数据类型决定了这个数据占用的字节数,以及计算机将如何解释这些字节。num的类型是int,因此将被解释为 一个整数。
3、内存数据的名称
内存的名称就是变量名。实质上,内存数据都是以地址来标识的,根本没有内存的名称这个说法,这只是高级语言提供的抽象机制 ,方便我们操作内存数据。而且在C语言中,并不是所有的内存数据都有名称,例如使用malloc申请的堆内存就没有。
4、内存数据的地址
如果一个类型占用的字节数大于1,则其变量的地址就是地址值最小的那个字节的地址。因此num的地址是 0028FF40。 内存的地址用于标识这个内存块。
5、内存数据的生命周期
num是main函数中的局部变量,因此当main函数被启动时,它被分配于栈内存上,当main执行结束时,消亡。
C语言中,定义变量时,在变量名 前 写一个 * 星号,这个变量就变成了对应变量类型的指针变量。必要时要加( ) 来避免优先级的问题。
引申:C语言中,定义变量时,在定义的最前面写上typedef ,那么这个变量名就成了一种类型,即这个类型的同义词。
int a ; //int类型变量 a
int *a ; //int* 变量a
int arr[3]; //arr是包含3个int元素的数组
int (* arr )[3]; //arr是一个指向包含3个int元素的数组的指针变量
//-----------------各种类型的指针------------------------------
int* p_int; //指向int类型变量的指针
double* p_double; //指向idouble类型变量的指针
struct Student *p_struct; //结构体类型的指针
int(*p_func)(int,int); //指向返回类型为int,有2个int形参的函数的指针
int(*p_arr)[3]; //指向含有3个int元素的数组的指针
int** p_pointer; //指向 一个整形变量指针的指针
既然有了指针变量,那就得让他保存其它变量的地址,使用& 运算符取得一个变量的地址。
int add(int a , int b)
{
return a + b;
}
int main(void)
{
int num = 97;
float score = 10.00F;
int arr[3] = {1,2,3};
//-----------------------
int* p_num = #
float* p_score = &score;
int (*p_arr)[3] = &arr;
int (*fp_add)(int ,int ) = add; //p_add是指向函数add的函数指针
return 0;
}
指针赋值和int变量赋值一样,就是将地址的值拷贝给另外一个。指针之间的赋值是一种浅拷贝,是在多个编程单元之间共享内存数据的高效的方法。
int* p1 = & num;
int* p3 = p1;
//通过指针 p1 、 p3 都可以对内存数据 num 进行读写,如果2个函数分别使用了p1 和p3,那么这2个函数就共享了数据num。
空指针
指向空,或者说不指向任何东西。在C语言中,我们让指针变量赋值为NULL表示一个空指针,而C语言中,NULL实质是 ((void*)0) , 在C++中,NULL实质是0。
换种说法:任何程序数据都不会存储在地址为0的内存块中,它是被操作系统预留的内存块。
#ifdef __cplusplus
#define NULL 0
#else
#define NULL ((void *)0)
#endif
指针变量的值是NULL,或者未知的地址值,或者是当前应用程序不可访问的地址值,这样的指针就是坏指针,不能对他们做解指针操作,否则程序会出现运行时错误,导致程序意外终止。
结构体指针有特殊的语法: -> 符号
如果p是一个结构体指针,则可以使用 p ->【成员】 的方法访问结构体的成员
任何一个指针变量在做 解地址操作前,都必须保证它指向的是有效的,可用的内存块,否则就会出错。坏指针是造成C语言Bug的最频繁的原因之一。
typedef struct
{
char name[31];
int age;
float score;
}Student;
int main(void)
{
Student stu = {"Bob" , 19, 98.0};
Student*ps = &stu;
ps->age = 20;
ps->score = 99.0;
printf("name:%s age:%d
",ps->name,ps->age);
return 0;
}
指针也是一种数据,指针变量也是一种变量,因此指针 这种数据也符合前面 变量和内存 主题中的特性。 这里我只想强调2个属性: 指针的类型,指针的值。
1、数组名作为右值的时候,就是第一个元素的地址。
int main(void)
{
int arr[3] = {1,2,3};
int*p_first = arr;
printf("%d
",*p_first); //1
return 0;
}
函数的指针
每一个函数本身也是一种程序数据,一个函数包含了多条执行语句,它被编译后,实质上是多条机器指令的合集。在程序载入到内存后,函数的机器指令存放在一个特定的逻辑区域:代码区。既然是存放在内存中,那么函数也是有自己的指针的。
void echo(const char *msg)
{
printf("%s",msg);
}
int main(void)
{
void(*p)(const char*) = echo; //函数指针变量指向echo这个函数
p("Hello "); //通过函数的指针p调用函数,等价于echo("Hello ")
echo("World
");
return 0;
}