文章目录

  • 一. 前言
  • 二. 第一个C语言程序
  • 三. 数据类型
  • 四. 变量和常量
    • a)变量
      • 1)局部变量
      • 2)全局变量
    • b)常量
      • 1)字面常量(相当于直接写)
      • 2)const修饰的常量
      • 3)#define定义的标识符常量
      • 4)枚举常量
  • 五. 字符串+转义字符+注释
    • a)字符串
      • 1)字符数组
    • b)转义字符
    • c)注释
  • 六. 选择语句(分支语句)
    • a)if语句
    • b)switch语句
      • 1)default
  • 七. 循环语句
    • a)while语句
    • b)for语句
    • c)do ... while语句
    • d)goto语句
  • 八. 函数
    • a)函数分类
      • 1)库函数
      • 2)自定义函数
    • b)函数参数
      • 1)实际参数(实参)
      • 2)形式参数(形参)
    • c)函数调用
      • 1)传值调用
      • 2)传址调用
    • d)函数的嵌套调用和链式访问
      • 1)嵌套调用
      • 2)链式访问
    • e)函数的声明和定义
      • 1)函数声明
      • 2)函数定义
    • f)函数递归
  • 九. 数组
    • a)一维数组
      • 1)一维数组的创建
      • 2)一维数组的初始化
    • b)二维数组
      • 1)二维数组的创建
      • 2)二维数组的初始化
    • c)数组越界
    • d)数组作为函数参数
    • e)数组名
  • 十. 操作符
    • a)算术操作符
    • b)移位操作符
      • 1)左移
      • 2)右移
        • x1)逻辑移位
        • x2)算术移位
    • c)位操作符
      • 1)&:按位与
      • 2)|:按位或
      • 3)^:按位异或
    • d)赋值操作符
    • e)单目操作符
      • 1)!逻辑反操作
      • 2)sizeof
      • 3)~ 按(二进制)位取法
      • 4)++ 前置、后置++
      • 5)-- 前置、后置 --
      • 6)(类型)强制类型转换
      • 7)& 取地址操作符 * 解引用操作符
    • f)关系操作符
    • g)逻辑操作符
    • h)条件操作符
    • i)逗号表达式
    • j)下标引用、函数调用和结构成员
      • 1)下标引用[]
      • 2)函数调用()
    • k)表达式求值
      • 1)隐式类型转换
        • x1)整形提升
      • 2)算术转换
      • 3)操作符的属性
  • 十一. 常见关键字
    • a)auto
    • b)extern
    • c)register
    • d)signed
    • e)unsigned
    • f)static
      • 1)static修饰局部变量
      • 2)static修饰全局变量
      • 3)static修饰函数
    • g)union
    • h)void
    • i)typedef
  • 十二. define定义常量和宏
    • a)define定义常量
    • b)define定义宏
  • 十三. 指针
    • a)指针的基本认识
    • b)指针的意义
    • c)野指针
      • 1)指针未初始化
      • 2)指针越界访问
      • 3)指针指向的空间释放
    • d)如何规避野指针
      • 1)指针初始化
      • 2)小心指针越界
      • 3)指针指向空间释放即使置NULL
      • 4)避免返回局部变量的地址
      • 5)指针使用之前检查有效性
    • e)指针运算
      • 1)指针+-整数
      • 2)指针-指针
      • 3)指针的关系运算
    • f)指针和数组
    • g)二级指针
    • h)指针数组
  • 十四. 结构体
  • 十五. 补充
    • a)scanf函数
    • b)调试
      • 1)调试的基本步骤
      • 2)快捷键
        • x1)内存
        • x2)调用堆栈
        • x3)打断点
        • x4)常用快捷键
      • 3)常用的调试技巧
        • x1)使用assert
        • x2)尽量使用const
        • x3)养成良好的编码风格
        • x4)添加必要的注释
        • x5)避免编码的陷阱
      • 4)编译常见的错误
        • x1)编译型错误
        • x2)链接型错误
        • x3)运行时错误

一. 前言

  • 本文是作者初学C语言的笔记整理哦,已进行6次更新(还会不断更新,结束会说明哦),小伙伴们注意接收哦,另外有什么问题可以留下你的邮箱,我会及时查看哦,另外制作不易,一键三连哦~
  • 本文现已结束初阶C语言,接下来将进入进阶C语言

二. 第一个C语言程序

#include <stdio.h>int main()
{printf("初学C语言");return 0;
}

这里说明下:

  • 由于printf的使用,需要引入头文件#include <stdio.h>。头文件就是为了这个printf函数的实现

  • 在运行程序的时候,如果使用的是VS2013版本的,会发现反应很快,输出一闪而过,这时候就需要设置一下为了看到代码运行的结果。如果用的是VS2013以上的版本,则不需要设置,都已经配置好了。将其子系统那块改成控制台即可。

  • 一个工程中有且仅有一个main函数

    1. 一个工程中可以有多个.c文件
    2. 多个.c文件只能有一个main函数

三. 数据类型

代码 数据类型
char 字符数据类型
short 短整型
int 整型
long 长整型
long long 更长的整型
float 单精度浮点数
double 双精度浮点数
  • 每种类型的大小(用sizeof来计算,单位byte)

  • 注:C语言标准:sizeof(long) >= sizeof(int)

  • 注:sizeof 是关键字,操作符,不是函数

  • 计算机中的单位

English 名称 换算
bit 比特
byte 字节 1 byte = 8 bit
KB 千字节 1 KB = 1024 byte
MB 兆字节 1 MB = 1024 KB
GB 吉字节 1 GB = 1024 MB
TB 太字节 1 TB = 1024 GB
PB Petabyte 1 PB = 1024 TB
  • 计算机中识别二进制 - 0和1
  • 识别八进制 - 0-7
  • 识别十进制 - 0-9

四. 变量和常量

a)变量

  • 定义:有些数据一定可变:工资、年龄、体重
  • 变量的生命周期指的是变量的创建到变量的销毁之间的一个时间段

1)局部变量

  • 局部变量的作用域是变量所在的局部范围
  • 局部变量的生命周期是:进入作用域生命周期开始,出作用域生命周期结束

2)全局变量

  • 全局变量的作用域是整个工程
  • 全局变量的生命周期是:整个程序的生命周期

注意:

  • 局部变量global变量的定义没有什么问题
  • 当局部变量和全局变量同名的时候,局部变量优先使用

b)常量

  • 定义:有些数据一定不变:血型、性别、圆周率

1)字面常量(相当于直接写)

2)const修饰的常量

  • const修饰的常变量不能被修改,因为const定义的基本类型的变量保存的是实际的内存地址, 内存地址不能动
  • pai 被称为 const 修饰的常变量, const 修饰的常变量 在C语言中只是在语法层面限制了变量 pai 不能直接被 改变,但是 pai 本质上还是一个变量的,所以叫常变量

3)#define定义的标识符常量

  • #define定义的标识符不占内存,只是一个临时 的符号,预编译后这个符号就不存在了

4)枚举常量

  • 枚举常量的默认是从0开始,依次向下递增1的

五. 字符串+转义字符+注释

a)字符串

  • 定义:一串字符,用双引号括起来的一串字符
  • 字符串的结束标志是\0的转义字符
  • 计算字符串长度的时候,\0是结束标志,不算作字符串的内容

1)字符数组

  • 定义: 字符数组是一组相同类型的元素
  • 当方括号里面不写这个数组有几个元素的时候, 会根据后面数据的大小自动分配
  • \0是隐藏的
  • arr2的后面的内存是未知的,而arr1后面有着字 符串结束标志\0
  • 注:对于字符串来说,\0是至关重要的,后面一定要 有\0,不然后面的空间识别不出,当运行后就会 显示乱码

计算字符串的长度

  • 注:由于arr2后面没有\0字符串结束标志,则arr2是不会结束的,会一直走下去,而走下去是未知的,直到碰到结束标志才会停止,所以arr2打印出来的长度是一个随机值
  • 这个警告出来,是因为没有引入头文件<string.h>,引入就可以安全的使用strlen了

b)转义字符

  • 计算长度
  • 这里输出14是因为,\328看上去应该是一个八进制的数据,那应该算一个字符,可以\328的个位是8,而八进制里面只有0-7,没有8.所以\328看成\32转义字符和8,算两个字符
  • 打印一个单引号(\c是打印单个字符)
printf("%c\n", '\'');
  • 打印一个字符串,字符串内容是双引号
printf("%s\n", "\"");
  • ASCII码值

c)注释

推荐一本书《高质量C/C++编程指南》林锐PDF

  • 定义:用来解释复杂代码
  • //是C++的注释风格
  • /**/是C语言的注释风格 - 但不支持嵌套注释
  • 一般来说,习惯用//

六. 选择语句(分支语句)

a)if语句

  • 语法结构:
//第一种:
if (表达式)语句;//第二种:
if (表达式)语句1;
else语句2;//第三种:多分支
if (表达式1)语句1;
else if (表达式2)语句2;
else语句3;
  • C语言是如何表示真和假你? - 非0就是真,0就是假
  • 注:if、else这些语句都默认只控制一行,若想控制多行,就用{}包起来
  • 注:else和它离得最近的if匹配,不看缩进对齐

b)switch语句

  • 常常用于多分支的情况
  • 注意:switch和case后面一定要整型的,而且case后面 还需要是常量或者常量表达式
  • 字符也可以,因为字符底层存储的是ASCII码 值,值必须要是整型和常量
  • 这种情况是因为没人阻止case的时候,就会一直跑下去输入几,就从哪个入口进去,前面的不执行
  • 因此,在每一个case后面都要加上break
  • break语句的实际效果就是把语句列表划分为不同的分支部分

1)default

  • 所有case语句都不符合,但不会执行任何操作,为了看到是否正确,就可以加default,直接在下面写代码,若输入不符 合case语句,就执行default语句
  • 同时default没有顺序问题,放哪都行,默认放后面, 只要满足需求,想怎么写就怎么写

七. 循环语句

a)while语句

  • 执行流程

  • 在while循环中,break用于永久的终止循环在while循环中,continue的作用是跳过本次循环continue 后面的代码直接去判断部分,看是否进行下一次循环

  • 例子,打印0-100之间的奇数

#include <stdio.h>int main()
{int i = 0;while (i <= 100){if (1 == i % 2){printf("%d ", i);}i++;}return 0;
}

b)for语句

  • 表达式1为初始化部分,用于初始化循环变量的
  • 表达式2为条件判断部分,用于判断循环时候终止
  • 表达式3为调整部分,用于循环条件的调整

执行流程

  • for循环特点:初始化只有一次

c)do … while语句

执行流程

  • do…while循环是肯定要执行一次的,先不关三七二十一,先执行,再来判断是否要继续循环,另外循环语句可能是一段代码,用{}包起来

d)goto语句

  • C语言中提供了可以随意滥用的 goto语句和标记跳转的标号。从理论上 goto语句是没有必要的,实践中没有goto语句也可以很容易的写出代码
  • 但是某些场合下goto语句还是用得着的,最常见的用法就是终止程序在某些深度嵌套的结构的处 理过程
  • 比如:一次跳出两个循环或多个循环
  • 另外注意:goto语句只能在一个函数范围内跳转,不能跨函数

八. 函数

  • 特点:简化代码,代码复用

a)函数分类

1)库函数

  • IO函数 printf scanf getchar putchar
  • 字符串操作函数 strcmp strlen
  • 字符操作函数 toupper小写转大写
  • 内存操作函数 memcpy memcmp mesmset
  • 时间/日期函数 time
  • 数学函数 sqrt pow
  • 其他库函数

注意:库函数的使用必须调用头文件

  • 使用库函数的参考工具(如上)

2)自定义函数

  • 自定义函数和库函数一样,有函数名,返回值类型和函数参数。但是不一样的是这些都是我们自己来设计

b)函数参数

1)实际参数(实参)

  • 实参其实就需要传入地址,若改变,原来的值也会改变,因为是同地址

2)形式参数(形参)

  • 形参只需要传入数值,不会改变原先的值

c)函数调用

1)传值调用

2)传址调用

d)函数的嵌套调用和链式访问

  • 函数和函数之间可以根据实际的需求 进行组合的,也就是互相调用的

1)嵌套调用

  • 注意:函数可以嵌套调用,但不能嵌套定义

2)链式访问

  • 把一个函数的返回值作为另外一个函数的参数

例如:

  • 答案为4321
  • 由于printf返回的是打印在屏幕上的字符的个数

e)函数的声明和定义

1)函数声明

  1. 告诉编译器有一个函数叫什么,参数是什么,返回类型是什么。 但是具体是不是存在,函数声明决定不了
  2. 函数的声明一般出现在函数的使用之前。要满足先声明后使用
  3. 函数的声明一般要放在头文件中的

2)函数定义

  • 函数的定义是指函数的具体实现,交待函数的功能实现

f)函数递归

  • 一个过程或函数在其定义或说明中有直接或间接调用自身的,一种方法,它通常把一个大型复杂的问题层层转化为一个与原问题相似的规模较小的问题来求解。
  • 只需少量的程序就可描述出解题过程所需要的多 次重复计算,大大地减少了程序的代码量
  • 递归的主要思考方式在于:把大事化小

递归的两个必要条件

  1. 存在限制条件,当满足这个限制条件的时候,递归便不再继续。
  2. 每次递归调用之后越来越接近这个限制条件

九. 数组

  • C语言中给了数组的定义:一组相同类型元素的集合
  • C语言规定:数组的每个元素都有一个下标,下标是从0开始的
  • 因此,数组可以通过下标进行访问
  • 数组的大小可以通过计算得到,用sizeof,总大小 / 首元素大小
  • 不能用strlen来求,因为strlen求的是字符串的大 小,而字符串是有结束符号的,而数组里是没有 字符串结束符号\0

  • 不完全初始化,剩余默认为0
  • 除号两端都是整数,执行整数除法,如果有一端是小数,执行小数除法

a)一维数组

  1. 一维数组在内存中是连续存放的
  2. 随着数组下标的增长,地址是由低到高的

1)一维数组的创建


  • 注意:一定要用常量表达式
  • 这种变量的表达式dev C++支持,C99也支持,VS不支持变长数组
  • 变长数组 - 数组的大小是变量
  • 数组创建,在C99标准之前, [] 中要给一个常量才可以,不能使用变量。在C99标准支持了变长数组的概念

2)一维数组的初始化

b)二维数组

  • 二维数组随着数组下标的增长,地址也是由低到高的

1)二维数组的创建

2)二维数组的初始化

  • 二维数组如果可以初始化,行可以省略,但列不能省略

c)数组越界

  • 数组的下标是有范围限制的
  • 数组的下规定是从0开始的,如果数组有n个元素,最后一个元素的下标就是n-1
  • 所以数组的下标如果小于0,或者大于n-1,就是数组越界访问了,超出了数组合法空间的访问
  • 注意:C语言本身是不做数组下标的越界检查,编译器也不一定报错,但是编译器不报错,并不意味着程序就是正确的

d)数组作为函数参数

  • 数组传参的时候,传递的其实是数组首元素的地址
  • 数组传参一般也要传入总大小,即sizeof。因此sizeof需要在主函数里创建

e)数组名

  • 数组名是数组首元素地址

  • &arr[0]与arr的返回值相同,两者的意思相同,而&arr和arr的返回值相同,但表达的意思不同
  • arr取出来的是首元素的地址
  • &arr取出来的是整个数组的地址,而整个数组的 地址,也是从首元素开始,所以地址就是首元素 的地址

但也有两个例外

  1. sizeof(数组名),计算整个数组的大小,sizeof内部单独放一个数组名,数组名表示整个数组
  2. &数组名,取出的是数组的地址。&数组名,数组名表示整个数组

  • arr+1取出来的地址与arr只相差4
  • &arr+1取出来的地址与&arr相差了40,即相差整个数组

十. 操作符

a)算术操作符

  • 加 减 乘 除 取余(+ - * / %)
  1. 除了 % 操作符之外,其他的几个操作符可以作用于整数和浮点数
  2. 对于 / 操作符如果两个操作数都为整数,执行整数 除法。而只要有一边是浮点数执行的就是浮点数除法
  3. % 操作符的两个操作数必须为整数。返回的是整除之后的余数

b)移位操作符

  • 右移 左移(>> <<)

1)左移

  • 二进制移动位数,总体移,左移:左边抛弃、右边补0

2)右移

  • 编译器中一般采用算术移位

x1)逻辑移位

  • 左边用0填充,右边丢弃

x2)算术移位

  • 左边用原该值的符号位填充,右边丢弃

注意点:

  1. 移位操作符的操作数只能是整
  2. 参与左移或者右移的操作符,在没被赋值的情况下,不会改变原先的值,即b = a << 1。a的值不变
  3. 不管左移还是右移,都是补码在移动,因此要注意负数先将其转换成补码,再来运算

c)位操作符

1)&:按位与

  • 参与运算的两数各对应的二进位相与。只要对应的二个二进位都为1时,结果位就为1

2)|:按位或

  • 参与运算的两数各对应的二进位相或。只要对应的二个二进位有一个为1时,结果位就为1

3)^:按位异或

  • 两个相应的二进制位值不同则为1,否则为0

注意点:

  • 都以补码的形式出现,即用补码来进行按位操作,如果是负数,还要考虑第一位,要转换成补码在来运算
  • 他们的操作数必须是整数

d)赋值操作符

e)单目操作符

1)!逻辑反操作

  • 0表示假,1表示真,把真变成假,把假变成真

2)sizeof

  • 是一个操作符,不是函数,用来计算类型或者变量的大小
  • 函数后面的括号不能删去,而操作符后面的括号 可以省去(判别是否为函数的方法)
  • 一个数组的大小为4byte(字节)
  • short的单位为2字节
  • sizeof括号里是不进行运算的

3)~ 按(二进制)位取法

  • 把所有二进制中数字,1变成0,0变成1
  • 0的二进制:0000000000000000000000000000000
  • 按位取法转换后:11111111111111111111111111111111

补充:整数在内存中存储的是补码~,所以要将其转换成原码

  • 一个整数的二进制表示有三种:原码、反码、补码
  • 因为一个数组大小为4个字节,也就是32bit,转换成二进制就是32位
  • 注:正整数:原码、反码、补码相同

4)++ 前置、后置++

  • 前置++ 先++,后使用

  • 后置++ 先使用,后++

5)-- 前置、后置 –

  • 同理于4)++前置、后置++

6)(类型)强制类型转换

7)& 取地址操作符 * 解引用操作符

f)关系操作符

  • 个等号是赋值,两个等号是判断
  • 字符串的相等需要用到strcmp函数,不能用两个等号判断

g)逻辑操作符

  • 逻辑操作符(0为假,1为真)
  1. && - 逻辑与(只有两个都为真时才为真)
  • 当逻辑与已经判断为假时,后面的就不用在进行了
  1. || - 逻辑或(只有两个都为假才为假)
  • 当逻辑或为真时,后面就不用在进行了

h)条件操作符

  • exp1 成立,exp2表达式计算,整个表达式的结果是:exp2的结果
  • exp1不成立,exp3表达式计算,整个表达式的结果是:exp3的结果

i)逗号表达式

  • 逗号隔开的一串表达式
  • 从左到右依此计算的
  • 整个表达式的结果是最后一个表达式的结果
  • 有些时候可能前面的表达式并没有作用,但是还是要注意看

j)下标引用、函数调用和结构成员

1)下标引用[]

  • 操作数:一个数组名 + 一个索引值

2)函数调用()

  • 接受一个或者多个操作数:第一个操作数是函数名,剩余的操作数就是传递给函数的参数

k)表达式求值

  • 在使用这些操作符的时候,需要注意各种运算顺序

1)隐式类型转换

  • C的整型算术运算总是至少以缺省整型类型的精度来进行的。为了获得这个精度,表达式中的字符和短整型操作数在使用之前被转换为普通整型,这种转换称为整型提升

x1)整形提升

  • 整形提升是按照变量的数据类型的符号位来提升的

  • 按照符号位来提升,符号位为0就全为0, 符号为1,就高位补充1
  • 都是用补码进行整型提升,因此负数要格外注意
  • 只有当自身的大小不足int类型的大小(4个字节)才需要进行整形提升
  • 比int大的不需要整形提升
  • 而需要整形提升的只有char类型和short类型,因为char类型是1个字节,short类型是2个字节

  • +c和-c是参与运算的,因此需要整型提升
  • %u就是打印一个无符号数
  • %d是打印有符号整数

2)算术转换

  • 如果某个操作符的各个操作数属于不同的类型, 那么除非其中一个操作数的转换为另一个操作数的类型,否则操作就无法进行

  • 这个是向上转换的,比如int和float进行组合,就需要将int转换成float类型
  • 如果某个操作数的类型在上面这个列表中排名较低,那么首先要转换为另外一个操作数的类型后执行运算

3)操作符的属性

复杂表达式的求值有三个影响的因素

  1. 操作符的优先级
  2. 操作符的结合性
  3. 是否控制求值顺序
  • 两个相邻的操作符先执行哪个?取决于他们的优先级。如果两者的优先级相同,取决于他们的结合性。操作符优先级

  • 从上往下,优先级是从高到低
  • 结合性
  1. N/A:说明无结合性,不需要考虑结合性
  2. L-R:从左向右结合
  3. R-L:从右向左结合
  • 是否控制求值顺序:就是当前面的判断可以代表 全部时,后面的就可以不需要进行
  • 有4个:逻辑与、逻辑或、条件操作符、逗号操作符

十一. 常见关键字

  • C语言提供的,不能自己创建关键字
  • 关键字不能做变量名

a)auto

  • 自动的 - 每个局部变量都是auto修饰的

b)extern

  • 用来声明外部符号的
  • 声明不需要指定的值
extern int g_val;

c)register

  • 寄存器关键字

d)signed

  • 有符号的,比如10,-20

e)unsigned

  • 无符号的

f)static

  • 静态的

1)static修饰局部变量

  • 改变了局部变量的生命周期(本质上改变了变量的存储类型)
  • 本身局部变量在所在范围结束后,就会自动销毁,而static修饰局部变量后,就不会销毁,直到程序结束
  • 让静态局部变量出了作用域依然存在,到程序结束,生命周期才结束

2)static修饰全局变量

  • 使得整个全局变量只能在自己所在的源文件(.c) 内部可以使用,而其他源文件不能使用
  • 经过static修饰后
  • 全局变量,在其他源文件内部可以被使用。是因为全局变量具有外部链接属性,但是被static修饰后,就变成了内部链接属性,其他源文件就不能链接到整个静态的全局变量了

3)static修饰函数

  • 使得函数只能在自己所在的源文件内部使用,不能在其他源文件内部使用
  • 本质上,static是将函数的外部链接属性变成了内部链接属性!(和static修饰全局变量一样)

g)union

  • 联合体(共用体)

h)void

  • 无-空

i)typedef

  • 类型定义(类型重命名)
  • 将 unsigned int 重命名为 u_int

补充:

  • define - 是不是关键字?NO - 预处理指令
  • include - 是不是关键字?NO - 预处理指令

十二. define定义常量和宏

a)define定义常量

b)define定义宏

十三. 指针

a)指针的基本认识

  • 内存怎么编号?
    32位 - 32根地址线 - 物理线 - 通电 - 正电1/负电0
    64位同理
  • 一个这样的内存单元多大
  • 指针都是4个字节(32位)
  • 一个内存单元是一个字节,然后分配地址
  • 打印地址
  • 取出变量地址:a有4个字节,每一个字节代表一个地址,取出来的是较小的地址(第一个地址)
  • %p专门用来打印地址
  • pa用来存放地址,在C语言中叫pa是指针变量
  • *说明pa是指针变量
  • int 说明pa指向的对象是int类型的

储存地址,需要定义指针变量

  • 指针还可以解引用,可以间接改变数值

总结:

d)如何规避野指针

1)指针初始化

2)小心指针越界

3)指针指向空间释放即使置NULL


  • 当他指向的空间被释放的时候,也指向空指针指向有效空间,就给有效地址
  • 因此要么空指针,要么有效地址
  • 因此给他一个if判断,判断是不是空指针,不是空指针的时候才是有效地址

4)避免返回局部变量的地址

5)指针使用之前检查有效性

e)指针运算

1)指针±整数

2)指针-指针

3)指针的关系运算

  • 实际在绝大部分的编译器上是可以顺利完成任务的,然而我们还是应该避免这样写,因为标准并不保证它可行
  • 标准规定:允许指向数组元素的指针与指向数组最后一个元素后面的那个内存位置的指针比较,但是不允许与指向第一个元素之前的那个内存位置的指针进行比较
  • 指针往前越界不合适 往后越界时为了拿到地址

f)指针和数组

g)二级指针

h)指针数组

十四. 结构体

  • 使得C语言有能力描述复杂对象


    说明:
  • 打印单精度就%f , 打印双精度就%lf, 这是字母L,不是数字1


结构的声明

  • struck是固定的语法结构 注意后面还有分号;定义创建了一个自定义的类型
  • 结构的成员可以是标量、数组、指针,甚至是其他结构体
  • print1是传值调用 print2是传址调用 print2更好
  • print1传入是实参传给形参,s有多大,t就要有多大空间
  • print1的改变不会影响s,改变不了s
  • 而print2传址,就是传入地址,没有开多大的空 间,因为地址一般为4个字节
  • 而print2还可以改变s的各种值
  • 函数传参的时候,参数是需要压栈的,如果传递一个结构体对象的时候,结构体过大,参数压栈的系统开销比较大,所以会导致性能的下降。
  • 因此结构体传参的时候,要传结构体的地址,即传址调用

压栈

十五. 补充

a)scanf函数

  • 在VS中,直接使用会报错
  • 这个提示要求我们使用scanf_s函数,然而scanf_s函数由VS编译提供,而不是C语言标准规定的
  • 要想使用scanf函数不报错,就得在源文件的第一行加上:
  • #define _CRT_SECURE_NO_WARNINGS 1
  • 而为了方便,直接将这个代码放入在创建源文件时就自动生成
  • 找到newc++ file.cpp这个文件,将代码放入即可,若必须管理员才能修改,就将其复制出来在外部修改,在粘贴回去替换。修改完后就会发现创建源文件就会自带上这个代码。找不到这个文件可以使用everything软件查找
  • 注:一般在后面的参数+&,因为对于scanf函数,它将参数视为地址

b)调试

1)调试的基本步骤

  1. 发现程序错误的存在
  2. 以隔离、消除等方式对错误进行定位
  3. 确定错误产生的原因
  4. 提出纠正错误的解决办法
  5. 对程序错误予以改正,重新测试

2)快捷键

x1)内存

x2)调用堆栈

x3)打断点

  • 设置条件,F5调试直接跳到此步

x4)常用快捷键

3)常用的调试技巧

x1)使用assert

  • 断言 - 就是判断条件,为假就报错,为真什么事都没有
  • 就是添加限制条件,触发就报错
  • 比如说strcpy就不能copy空指针

x2)尽量使用const

  • const修饰指针变量
  1. const如果放在*的左边,修饰的是指针指向的内容,保证指针指向的内容不能通过指针来改变。但是指针变量本身的内容可变
  2. const如果放在*的右边,修饰的是指针变量本身,保证了指针变量的内容不能修改,但是指针指向的内容,可以通过指针改变

x3)养成良好的编码风格

x4)添加必要的注释

x5)避免编码的陷阱

4)编译常见的错误

x1)编译型错误

  • 直接看错误提示信息(双击),解决问题。或者凭借经验就可以搞定。相对来说简单

x2)链接型错误

  • 看错误提示信息,主要在代码中找到错误信息中的标识符,然后定位问题所在。一般是标识符名不存在或者拼写错误

x3)运行时错误

  • 借助调试,逐步定位问题。最难搞

C语言基础入门——保姆式教程(2022版最全最新整理)相关推荐

  1. R语言基础入门(学习笔记通俗易懂版)

    文章目录 R语言预备知识 获取工作目录 设置工作目录 注释 变量名的命名 赋值 变量的显示 查看与清除变量 函数帮助文档查询 函数 安装R包 文件的读取 文件的输出 软件的退出与保存 R语言语法 向量 ...

  2. Xilinx FPGA平台DDR3设计保姆式教程(1)DDR3基础简介

    如果我们只是拿来用ddr搬砖,那么它就简单,知道IP怎么使用就好,但是要想知其所以然,理论知识是必备的,这也是我们初学者所欠缺的东西,慢慢修炼吧! 汇总篇: Xilinx平台DDR3设计保姆式教程(汇 ...

  3. C 语言从入门到精通教程(2021 )

    C 语言从入门到精通教程(2021年) 文章目录 计算机常识 什么是计算机程序 ? 什么是计算机语言 ? 常见的计算机语言类型有哪些 ? 什么是C语言? C语言历史 C语言标准 C语言现状 为什么要学 ...

  4. Android基础入门视频培训教程-刘志远-专题视频课程

    Android基础入门视频培训教程-146257人已学习 课程介绍         Android基础入门视频培训课程,该教程内容涵盖Android入门开发基本技能(环境搭建.Lineralayout ...

  5. Unified Functional Testing(UFT)15.0.2入门保姆级教程(一),图文详解。QTP

    UFT入门之侦测器(ObjectSpy)及录制第一个脚本 实验说明 1.Quick Test Pro(QTP)11.5后更名为Unified Functional Testing(UFT) 2. 实验 ...

  6. C语言基础入门学习笔记

    前言 我是一个初中生,过完暑假就是一个高一的学生了.在这个暑假里,我学习了韦东山老师和唐佐林老师的课程,所以我写下这个笔记来记录自己的成长历程. C语言基础入门学习笔记 格式 #include < ...

  7. jenkins流水线(jenkinsfile)详解,保姆式教程

    jenkins流水线(jenkinsfile)详解 在学习本篇文章的时候,可以去看看jenkins官网的文档,jenkins官网支持中文,观看十分便捷 此教程使用的是gitee+docker+jenk ...

  8. 圣诞节快到了,用Python给好友做一个圣诞树小程序吧【保姆式教程】

    圣诞节快到了,用Python给好友做一个圣诞树小程序吧[保姆式教程] 马上圣诞节了,一个人的圣诞节可能会有些孤独,我来教你怎么用代码写一棵超级治愈的圣诞树. 话不多说,下面来看具体怎么实现吧! 文章目 ...

  9. Node.js的完全卸载与下载安装及各种npm、nvm、nrm配置(保姆式教程---提供全套安装包)---node.js的安装与配置(0)

    Node.js的完全卸载与下载安装及各种npm.nvm.nrm配置(保姆式教程-提供全套安装包)-node.js的安装与配置(0) node的卸载 1.打开控制面板 我的电脑右键--->属性-- ...

最新文章

  1. 网站优化数据分析不建议你遗落这三点
  2. HTML5中figure标签使用实例
  3. EasyX实现推箱子游戏
  4. 写一个“特殊”的查询构造器 - (四、条件查询:复杂条件)
  5. 分布式资源调度—YARN框架
  6. tyvj1102 单词的划分
  7. 参加双车项目的一些感触
  8. 打开数据库_数据库客户端navicat遇到问题怎么办?
  9. JPA 2.1和Java EE 7中的JPQL增强功能(第1部分– JOIN ON)
  10. 什么是负边沿触发_用好示波器必须学会的知识:触发方式
  11. jQuery:从零开始,DIY一个jQuery(2)
  12. 吸毒女5次搬家躲粉友:想给女儿干净环境
  13. 基于SSM的在线课程学习系统
  14. 我的CSDN原创高质量免积分下载资源列表(持续更新)
  15. 随手记:Ubuntu16.04.1安装Chrome浏览器以及解决root下无法启动的问题
  16. python day 5
  17. LIS3DH运动检测调试过程
  18. 判断机型,支持最新设备(iPhone SE Gen2 和 iPad Pro 11 Gen2、iPad Pro 12.9 Gen4)
  19. Floyd-傻子也能看懂的弗洛伊德算法(转)
  20. 走进黑客工具箱:使用 Whatweb 和 Acunetix 加固您的 Web 应用程序

热门文章

  1. 英语语法——句子分类
  2. python 1、输入a,b,c解二元一次方程;2、克莱姆法则解线性方程;3、输入今天之后未来的天数,显示今天是星期几;4、输入一个数,检测是否能被5和6整除;5、输入人民币和美元的汇率和转换金额;
  3. 包裹侠查快递单号_包裹侠快递查询
  4. 搭建SSH,SSZ架构需注意数据库的编码问题
  5. android studio中注解处理器的调试配置
  6. 股票只有两个字:“等待”
  7. Mac创建自签名的代码证书
  8. photoshop cs3 打字不显示问题
  9. Python 用 OpenCV 实现 PS 高光/阴影选区
  10. Pytorch:定义的网络结构层能否重复使用