目录
C语言::
计算机内存数值存储方式与进制转换
1.二进制 八进制 十六进制
进制就是进位制,是人们规定的一种进位方法。对于任何一种进制—X进制就表示某一位置上的数运算时是逢X进一位。十进制就是逢十进一,十六进制是逢十六进一,二进制是逢二进一。
二进制
二进制,缩写BIN,二进制是计算机技术中广泛采用的是一种数制。二进制数据是用0和1两个数码来表示的数。进位规则是“逢二进一”,借位规则是“借一当二”。
当前的计算机系统使用的基本上是二进制系统,数据在计算机中主要以补码的形式存储。
术语
bit(比特) | 一个二进制代表一位,一个位只能表示0或1 |
byte(字节) | 1byte=8bit 字节是计算机存储数据的最小单位 |
KB(千字节) | 1KB=1024byte |
MB(兆字节) | 1MB=1024KB |
GB(吉字节) | 1GB=1024MB |
TB(太字节) | 1TB=1024GB |
十进制转化成二进制的基本方法:除二反序取余法 用十进制数除以2,分别取余数和商,商为0时,将余数倒着数就是转化后的结果。
二进制转成十进制的基本方法:权值法 将一个二进制数依次从末尾开始乘以2的n次方相加,n从0开始。
例:111000 == 0 * 2^0 + 0 * 2^1 + 0 * 2^2 + 1 * 2^3 + 1 * 2^4 + 1 * 2^5 == 56 |
八进制
八进制,缩写OCT,一种以8为基数的计数法,采用0,1,2,3,4,5,6,7八个数字,逢八进一。编程语言中常常以数字0表明该数字是八进制。
八进制的数和二进制数可以按位对(八进制一位对应二进制三位),因此常应用在计算机语言中。
十进制转化八进制的基本方法:除八反序取余法,用十进制数除以8,分别取余数和商,商为0时,将余数倒着数就是转化后的结果。
八进制转化成十进制的基本方法:权值法,将一个二进制数依次从末尾开始乘以8的n次方相加,n从0开始。
例:1067 == 7 * 8^0 + 6 * 8^1 + 0 * 8^2 + 1 * 8^3 == 567 |
十六进制
十六进制,缩写HEX,同我们日常生活中表示方法不一样,它由0—9,A—F组成,字母不区分大小写。与十进制的关系是:0—9对应0—9,A—F对应的是10—15。
十六进制的数和二进制数可以按位对应(十六进制一位对应二进制四位),因此常应用在计算机语言中。
八进制的数和二进制数可以按位对(八进制一位对应二进制三位),因此常应用在计算机语言中。
十进制转化成十六进制的基本方法:除十六反序取余法,用十进制数除以16,分别取余数和商,商为0的时候,将余数倒着数就是转化后的结果。
十六进制转化成十进制的基本方法:权值法,将一个十六进制数依次从末尾开始乘以16的n次方相加,n从0开始。
例:162E ==E * 16^0 + 2 * 16^1 + 6 * 16^2 + 1 * 16^3 == 5678
二进制 八进制 十六进制快速转化的技巧:8421法则。
二进制快速转化成八进制:将三个二进制位转化成一个八进制位
八进制快速转化成二进制:将一个八进制位转化成三个二进制位
二进制快速转化成十六进制:将四个二进制位转化成一个十六进制位
八进制快速转化成十六进制:八进制先按照8421法则转化成二进制再转化成十六进制
C语言如何表示相应进制数
十进制 | 以正常数字1—9开头,如123 |
八进制 | 以数字0开头,如0123 |
十六进制 | 以0x开头,如0x123 |
二进制 | C语言不能直接书写二进制数 |
#include<stdio.h>
int main()
{
int a = 123; //十进制方式赋值
int b = 0123; //八进制方式赋值
int c = 0xABC;//十六进制方式赋值
//如果在printf中输出一个十进制数那么用%d,八进制用%o,十六进制用%x
printf("十进制:%d\n",a);
printf("八进制:%o\n", b);
printf("十六进制:%x\n",c);
return 0;
}
2.原码 反码 补码
原码
一个数的原码(原始的二进制码)有如下特点:
(1).最高位作为符号位,0表示正,1表示负。
(2)其他数值部分就是数值本身绝对值的二进制数。
(3)负数的原码是在其绝对值的基础上,最高位变为1.
原码缺陷:不便于加减运算
反码
(1).对于正数,反码与原码相同
(2)对于负数,符号位不变,其他位按位取反
反码也不便于加减运算,通常用来求补码的中间过渡。
补码
在计算机系统中数值一律用补码存储。
补码特点:
(1).对于正数,原码,反码,补码相同
(2)对于负数,其补码为它的反码加1
(3)补码符号位不动,其他位按位取反再加1得到原码
补码的意义
不管以原码方式存储,还是以反码方式存储,0也有两种表示方式。但是如果以补码方式存储,补码统一了零的编码。
在计算机系统中,数值一律用补码方式存储,主要原因是:
(1).统一了零的编码
(2)将符号位和其他位统一处理
(3)将减法运算变为加法运算
(4)两个用补码表示的数相加时,如果最高位(符号位)有进位,则进位被舍弃
3.数值溢出
(1).有符号数:有符号数是最高位为符号位,0代表正数,1代表负数。
(2).无符号数:无符号数最高位不是符号位,而就是数的一部分,无符号数不可能是负数。
(3).数值溢出:当超过一个数据类型能存放的最大范围时,数值会溢出。
(4).有符号位最高位溢出的区别:符号位溢出会导致数的正负发生改变,但最高位的溢出会导致最高位丢失。
C语言的代码框架、编译流程及其初识CPU内部结构与寄存器
1.第一个C语言程序的代码剖析
#include<stdio.h>
int main()
{
printf("hello world\n");
return 0;
}
(1)include头文件包含
#include的意思是头文件包含,#include<stdio.h>代表包含stdio.h这个头文件。std是一个标准库,i:input,o:output,标准输入输出库,.h头文件。
#include< >与#include" " 的区别:< > 表示导入系统文件," "表示导入自定义文件。
(2) main函数
main函数是C语言的程序的入口,程序的主函数,程序有且只有一个主函数,( )里面表示函数的参数,函数的参数可以有多个,中间用逗号分隔。
(3) {}括号,程序体和代码块
{}叫代码块,一个代码块内部可以有一条或者多条语句,C语言每句可执行代码都是“ ;”分号结尾,所有的#开头的行,都代表预编译指令,预编译指令行结尾是没有分号的,所有的可执行语句必须是在代码块里面。
(4) 注释
//叫行注释,注释的内容编译器是忽略的,注释的主要作用是在代码中加一些说明和解释,有利于代码的阅读。
/**/叫块注释,块注释是C语言标准的注释方法,行注释是从C++语言借鉴过来的。
(5)printf函数
printf是stdio.h系统提供的函数,表示在标准输出设备上打印字符串,“ ”称为字符串,\n的意思是回车换行。
(6)return语句
return如果出现在其他函数中表示函数的结束,如果出现在main函数中表示程序结束。0表示函数的返回值,要和函数的返回值类型对应,在main函数中,return 0 代表程序执行成功,return -1代表程序执行失败
2.C语言编译过程
C语言编译成可执行程序经过4步:
(1)预处理:宏定义展开,头文件展开条件编译,同时将代码中的注释删除,这里并不会检查语法。
(2)编译:检查语法,将预处理后的文件生成汇编文件。
(3)汇编:将汇编文件生成二进制文件。
(4)链接:C语言写的程序是依赖各种库的,编译之后还需要把库链接到可执行程序中。
3.CPU内部结构与寄存器
64位和32位系统区别
CPU对外是通过总线(地址、控制、数据)来和外部设备交互的,总线的宽度是8位,同时CPU的寄存器也是8位,那么这个CPU就叫8位CPU。
如果总线是32位,寄存器也是32位,那么这个CPU就是32位CPU,所有的64位CPU兼容32位的指令,32位要兼容16位的指令,所以在64位的CPU上是可以识别32位指令的,但反过来,64位的软件不能运行在32位的CPU上。
寄存器名字
寄存器,高速缓存,内存三者关系
随着技术的增进 CPU的计算速度越来越快 导致内存的读取数据速度跟不上就有了寄存器和高速缓存,按与CPU远近来分,离得最近的是寄存器,然后是高速缓存,最后内存,CPU计算时,先预先要把用的数据从硬盘读到内存,然后再把即将要用的数据读取到寄存器。于是CPU<——>寄存器<——>内存,这就是它们之间的信息交换。
为什么要有缓存呢?因为如果经常操作内存中的同一地址数据,就会影响速度,于是就在寄存器与内存之间设置一个缓存。因为从缓存中提取数据的速度远高于内存。当然缓存的价格也远高于内存。
C语言的基本概念
1.数据类型
关键字
数据类型
数据类型的作用:编译器预算对象(变量)分配的内存空间大小。
2.变量与常量
变量:
在程序运行过程中,其值可变,变量在使用前必须先定义,定义变量前必须有相应的数据类型
标识符命名规则:
标识符不能是关键字,标识符只能由字母、数字、下划线组成,第一个字符不能是数字,标识符要区分大小写。
定义变量的方法:
数据类型 + 变量名 = 数值;
int age = 150;
float weight = 45.5f;
char ch = 'w';
变量的分类:
局部变量和全局变量
若局部变量和全局变量重名,局部变量优先使用。
#include<stdio.h>
int global = 2019;//全局变量
int main()
{
int local = 2018;//局部变量
int global = 2020;//局部变量
printf("global = %d\n",global);
return 0;
}
变量的使用
#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;
}
变量的作用域和生命周期
作用域:
一段程序的代码并不总是有效的,限定这个名字的可用性的代码就是这个名字的作用域。局部变量的作用域就是变量所在的局部范围,全局变量的作用域是整个程序。
生命周期
变量的生命周期指的是变量的创建到变量的销毁之间的一个时间段。局部变量的生命周期:进入作用域生命周期开始,出作用域生命周期结束。全局变量对1生命周期:整个程序的生命周期。
常量
在程序运行过程中,其值不能改变的量称为常量。C语言的常量和变量的形式有所差异。
C语言的常量分为如下几种:
字面常量 const修饰的常量 #define定义的标识符常量 枚举常量
#include<stdio.h>
enum Sex
{
MALE,
FEMALE,
SECREAT,
};
//括号中的MALE,FEMALE,SECREAT是枚举常量
int main()
{
//字面常量演示
3.14;//字面常量
1000;//字面常量
//const修饰的常变量
const float pai = 3.14f;//这里的pai是const修饰的常变量
pai = 5.14//是不能直接修改的
//#define的标识符常量演示
#define MAX 100
printf("MAX=%d\n", MAX);
//枚举常量演示
printf("%d\n", MALE);
printf("%d\n", FEMALE);
printf("%d\n", SECREAT);
//注:枚举常量的默认值是从0开始,依次向下递增的
return 0;
}
3.字符串、转义字符与注释
字符串
字符串是内存中一段连续的char空间,由双引号引起来的一段字符,以‘\0’结尾,如“China”,"program","$12.5".
字符串常量与字符常量不同
每个字符串的结尾,编译器会自动的添加一个结束标志位‘\0’,即‘a’包含两个字符‘a’和‘\0’.
#include<stdio.h>
int main()
{
char arr1[] = "code";
char arr2[] = { 'c','o','d','e' };
char arr3[] = { 'c','o','d','e','\0' };
printf("%s\n", arr1);
printf("%s\n", arr2);
printf("%s\n", arr3);
return 0;
}
转义字符
假设我们要在屏幕上打印一个目录:c:\code\test.c,我们要写的代码如下:
实际上程序的运行结果是这样的:
这里h不得不提一下转义字符。
上面的代码正确写法是:
#include<stdio.h>
int main()
{
printf("c:\\code\\test.c");
return 0;
}
下面我们来看一道笔试题
#include<stdio.h>
//程序输出什么
int main()
{
printf("%d\n", strlen("c:\test\628\test.c"));
return 0;
}
因为\t ,\62 被当作转义字符。 所以答案是14。
注释
优点:代码中有不需要的代码可以直接删除,也可以注释掉。
代码中有些代码比较难懂,可以加一些注释文字。
风格:C语言风格的注释:/*xxxxx*/
C++风格的注释://xxxxxxx
4.选择语句
C语言支持最基本的三种程序运行结构:顺序结构、选择结构、循环结构。
顺序结构:程序按顺序执行,不发生跳转。
选择结构:依据是否满足条件,有选择的执行相应功能。
循环结构:依据条件是否满足,循环多次执行某代码。
if...else语句 (switch语句在后续“分支循环语句”的博客中会重点提到)
#include<stdio.h>
int main()
{
int code = 0;
printf("你会去敲代码吗?(选择1或0):->");
scanf("%d", &code);
if (code == 1)
{
printf("坚持,你会有好offer\n");
}
else
{
printf("放弃,回家卖红薯\n");
}
return 0;
}
5.循环语句
C语言如何去实现循环
while语句 for语句 do...while语句(后两个在后续博客“分支循环语句”的博客中会重点提到)
while语句
#include<stdio.h>
int main()
{
printf("好好学习\n");
int line = 0;
while(line<=100000)
{
line++;
printf("我要继续努力敲代码\n");
}
if (line == 100000)
printf("好offer\n");
return 0;
}
6.函数
代码多使用函数的优点:1.避免冗余,省去重复代码的编写,降低代码重复率。
2.函数可以让程序更加模块,从而有利于程序的阅读,修改和完善。
#include<stdio.h>
int main()
{
int num1 = 0;
int num2 = 0;
int sum = 0;
printf("输入两个操作数:->");
scanf("%d %d", &num1, &num2);
sum = Add(num1, num2);
printf("sum=%d\n", sum);
return 0;
}
7.数组
数组定义
在程序设计中,为了方便处理数据把具有相同类型的若干变量按有序形式组织起来称之为数组。
数组就是在内存中连续的相同类型的变量空间。同一个数组所有的成员都是相同的类型,同时所有的成员在内存中的地址是连续的。
数组的使用
#include<stdio.h>
int main()
{
int i = 0;
int arr[10] = { 1,2,3,4,5,6,7,8,9,10 };
for (i = 0; i < 10; i++)
{
printf("%d ", arr[i]);
}
printf("\n");
return 0;
}
8.操作符
常用运算符分类
运算符类型 | 作用 |
算术运算符 | 用于处理四则运算 |
赋值运算符 | 用于将表达式的值赋给变量 |
比较运算符 | 用于表达式的比较,并返回一个真值或假值 |
逻辑运算符 | 用于根据表达式的值返回真值或假值 |
位运算符 | 用于处理数据的位运算 |
sizeof运算符 | 用于求字节 |
算术运算符
赋值运算符
比较运算符
逻辑运算符
注:位运算符在后续操作符的博客中会重点提到。
sizeof运算符
sizeof不是函数,所以不需要包含任何头文件,它的功能是计算一个数据类型的大小,单位为字节。sizeof的返回值是size_t
9.常见关键字
(1)关键字 typdef
typdef顾名思义是类型重命名
比如:
#include<stdio.h>
typedef unsigned int uint;
int main()
{
//观察num1和num2,这两个变量的类型是一样的
unsigned int num1 = 0;
uint num2 = 0;
return 0;
}
(2)关键字static
在C语言中 static是用来修饰变量和函数的·。修饰局部变量,称为静态局部变量,修饰全局变量,称为静态全局变量,修饰函数,称为静态函数。
static修饰局部变量
static局部变量的生命周期和程序运行周期一样,同时static局部变量的值只初始化一次,但可以赋值多次。
static局部变量若未赋以其值,则由系统自动赋值,数值型变量自动赋值为0,字符型变量赋值为空字符。
#include<stdio.h>
//代码1
void test()
{
int i = 0;
i++;
printf("%d ", i);
}
int main()
{
int i = 0;
for (i = 0; i < 10; i++)
{
test();
}
return 0;
}
//代码2
void test()
{
//static修饰局部变量
static int i = 0;
i++;
printf("%d ", i);
}
int main()
{
int i = 0;
for (i = 0; i < 10; i++)
{
test();
}
return 0;
}
static修饰全局变量
在函数外定义,作用范围被限制在所定义的文件中。
static全局变量的生命周期和程序运行周期一样,同时static全局变量的值只初始化一次。
#include<stdio.h>
//代码1
//add.c
int g_val = 2018;
//test.c
int main()
{
printf("%d\n", g_val);
return 0;
}
//代码2
//add.c
static int g_val = 2018;
//test.c
int main()
{
printf("%d\n", g_val);
return 0;
}
static修饰函数
在C语言中函数默认都是全局的,使用关键字static可以将函数声明为静态,函数定义为static就意味着这个函数只能在定义在这个函数的文件中使用,在其他文件中不能调用,即使在其他文件中声明这个函数也无用。
#include<stdio.h>
//代码1
//add.c
int Add(int x, int y)
{
return x + y;
}
//test.c
int main()
{
printf("%d\n", Add(2, 3));
return 0;
}
//代码2
//add.c
static int Add(int x, int y)
{
return x + y;
}
//test.c
int main()
{
printf("%d\n", Add(2, 3));
return 0;
}
10.define定义常量和宏
#include<stdio.h>
//#define定义标识符常量
#define MAX 1000
//#define定义宏
#define ADD(x,y) ((x)+(y))
int main()
{
int sum = ADD(2, 3);
printf("sum=%d\n", sum);
sum = 10 * ADD(2, 3);
printf("sum=%d\n", sum);
return 0;
}
11.内存布局
代码区(text)
存放CPU执行的机器指令,通常代码区是共享且只读的共享的目的是对于频繁被执行的程序,只需要在内存中有一份代码即可。只读的原因是防止程序意外的被修改指令。
初始化数据区(data段)
该区包含了在程序中明确被初始化的全局变量,已经被初始化的静态变量(全局静态变量和局部静态变量)和常量数据(如字符串常量)。
未初始化数据区(bss区)
存入的是全局未初始化变量和未初始化静态变量。未初始化数据区的数据在程序开始执行之前被内核初始化为0或NULL。
栈区(stack)
栈是一种先进后出的内存结构,由编译器自动分配和释放,因此局部变量的生命周期为申请到释放该段栈空间。存放的有局部变量,函数信息,函数参数,数组,指针。栈区大小通常为1M,Window操作系统中可扩展到10M,Linux操作系统中可扩展到16M。
堆区(heap)
堆是一个大容器,它的容量要远大于栈,但没有栈那样先进后出的顺序,用于动态内存分配。堆在内存中位于bss区和栈区之间。一般由程序员分配和释放,若程序员不释放,程序结束时由操作系统回收。
12.指针
内存
内存是电脑上特别重要的存储器,用来存储程序和设计,辅助CPU进行运算处理的重要部分。所以为了有效的使用内存,就把内存划分为一个个小的内存单元。每个内存单元的大小是1个字节,为了有效的访问到内存的每个单元,就给内存单元进行了编号,编号被称之为内存地址。
存储地址就需要定义指针变量。
指针的使用实例
#include<stdio.h>
int main()
{
int num = 10;
int* p = #
*p = 20;
return 0;
}
指针变量的大小
#include<stdio.h>
//指针变量的大小取决于地址的大小
//32位平台下地址是32个bit位(即4个字节)
//64位平台下地址是64个bit位(即8个字节)
int main()
{
printf("%d\n",sizeof(char*));
printf("%d\n",sizeof(int*));
printf("%d\n",sizeof(short*));
printf("%d\n",sizeof(double*));
}
//结论:指针大小在32位平台是4个字节,64位平台是8个字节
13.结构体
C语言给了自定义类型的能力 自定义中的其中一种类型叫做:结构体(struct)
结构体是把单一类型组合在一起的一种自定义的数据类型。
#include<stdio.h>
struct Stu //设计时并不占用空间大小
{
//成员
char name[20];
int age;
char sex[10];
char tele[12];
};
void print(struct Stu* ps)
{
printf("%s %d %s %s\n",(*ps).name,(*ps).age,(*ps).sex,(*ps).tele);
//-> 结构体指针变量->成员名
printf("%s %d %s %s\n",ps->name,ps->age,ps->sex,ps->tele);
}
int main()
{
struct Stu s = {"zhangsan",20,"nan","15596668862"};
//结构体对象.成员名
printf("%s %d %s %s\n",s.name,s.age,s,sex,s.tele);
print(&s);
return 0;
}
C语言编程训练(牛客网)
1.BC6——小飞机
#include<stdio.h>
int main()
{
printf(" **\n");
printf(" **\n");
printf("************\n");
printf("************\n");
printf(" * *\n");
printf(" * *\n");
return 0;
}
2.BC17——计算表达式的值
#include<stdio.h>
int main()
{
int a = 40;
int c = 212;
int r = (-8+22)*a-10+c/2;
printf("%d\n",r);
return 0;
}
3.BC18——计算带余除法
#include<stdio.h>
int main()
{
int a = 0;
int b = 0;
scanf("%d %d",&a,&b);
int m = a / b;
int n = a % b;
printf("%d %d",m,n);
return 0;
}
4.BC31——发布信息
#include <stdio.h>
int main()
{
printf("I lost my cellphone!\n");
return 0;
}
5.BC32——输出学生信息
#include<stdio.h>
int main()
{
printf("Name Age Gender\n");
printf("---------------------\n");
printf("Jack 18 man \n");
return 0;
}
6.BC84——计算Y的值
#include<stdio.h>
int main()
{
//输入
int x = 0;
int y = 0;
scanf("%d",&x);
//计算
if(x>0)
y=-1;
else if(x==0)
y=0;
else
y=1;
//输出
printf("%d\n",y);
return 0;
}
7.写一个函数求两个整数的较大值
#include <stdio.h>
int Max(int x, int y)
{
if (x > y)
return x;
else
return y;
}
int main()
{
int a = 0;
int b = 0;
scanf("%d %d", &a, &b);
int ret = Max(a, b);
printf("%d\n", ret);
}