C语言基础

C语言基础


目录

数制

基本数据类型

关于char的死循环

第一个C语言程序

scanf 函数的不安全性分析

变量及类型转换

浮点数(关于float型变量在内存中的存储)

位运算符


数制

对于一个 10 进制整型 int 数字,12 转化为二进制数字 0000 1100,八进制 0000 0014,十六进制:0x0C

反码补码,正数的补码反码都是一样的,区别在与负数的补码,对一个负数求补码至于要取绝对值然后取反加 1 就可。

例:-12 的补码是:1111 0100

ASCII 的取值范围为什么是 0-127?

因为为了提高代码的可移植性,无符号取值范围是 0 ~ 255,有符号的取值范围 -128 ~ +127,两个取值范围的交集就是 0 ~ 127,所以 ASCII 的取值范围正好在这个地方

基本数据类型

short、int、long、char、float、double 这六个关键字代表C语言里的六种基本数据类型。

在不同的系统上,这些类型占据的字节长度是不同的:

在32 位的系统上

short 占据的内存大小是2 个byte
int占据的内存大小是4 个byte
long占据的内存大小是4 个byte
float占据的内存大小是4 个byte
double占据的内存大小是8 个byte
char占据的内存大小是1 个byte

关于char的死循环

对于 char 类型来说, 占一字节(8位),取值范围为-128到127。由于数字在计算机中是以补码形式表示,并且char类型为有符号数,则一字节(8位)中的最高位为符号位。能表示的最大正数二进制形式为“01111111”,由于正数补码与原码相同,其原码同样为“01111111”,对应十进制为127;同理,能表示的最小负数二进制形式为“10000000”,由于这是补码形式,其原码对应为-128。如果是无符号数(unsigned n),那么当八位全部是 1 的时候,1111 1111 那么就是 255。

int main()
{
    for(char i = 0;i < 128;i++)
    {    
        printf(“%d ”,i);//为什么死循环
    }
    return 0;
}

 程序分析:

上述的for循环语句,i 的取值从0到127这阶段的循环语句执行正常。当i=128时,由于超出char取值范围,编译器会将ch值变为-128,仍然满足 < 128条件,继续执行循环,同时 i++。由于每次for循环 i 都自增( i++),i 值将会逐渐从-128递增到0,这时又回到了for循环的起始条件处( i =0),当再次递增到127后,i 值又会变为-128,以后不断循环。 从以上分析中可以看出,“ i++ ”语句并没有使i值一直增加,相反 i 值不断在“-128到127”中循环变化,使得 “i<128” 永远成立,程序陷入死循环。

第一个C语言程序

#include<stdio.h>
int main()
{
Printf(“hello world\n”);
Return 0;
}

(1)  #include<stdio.h>     //头文件:其作用是包含我们所需要的库函数 printf();
(2)  对于 main 函数来说,每一个可执行程序有且仅有一个 main 函数,返回值为int,但是对于 main 函数来说,可以不写 return 0;其他自己实现的函数,必须如果有返回值,那么一定要写 return。
(3)  printf()函数,分别打印各种类型是所需要的格式化符不一样。
(4)  每一个程序在从源码到执行所需要的过程:预编译,编译,汇编,链接 

scanf 函数的不安全性分析

通过scanf函数可以接受任意的键盘的输入,如果输入的长度超过了应用给定的缓冲区,就会覆盖其他数据区,这称为“堆栈溢出”“缓冲区溢出”。而且scanf函数有三个特点:
1. 取数据时遇到空格、回车、TAB就会停止;
2. scanf函数和都是从输入流缓冲区中读取数据的,而不是从键盘(终端)缓冲区读取值的。读取时遇到回车\n即结束,且回车\n会被读入输入缓冲数据流中,这样第二次的读入函数将输入缓冲区中的回车\n读取走了,没有等待键盘的二次输入。
3. scanf读取字符串时,会舍弃最后的回车符

变量及类型转换

变量其实只不过是程序可操作的存储区的名称。C 中每个变量都有特定的类型,类型决定了变量存储的大小和布局,该范围内的值都可以存储在内存中,运算符可应用于变量上。

变量的名称可以由字母、数字和下划线字符组成。它必须以字母或下划线开头。大写字母和小写字母是不同的,因为 C 是大小写敏感的。

例如:int a = 10;计算机会分配 4 个字节给变量a存储 10,且是二进制。在定义变量的时候,变量必须先定义后使用,定义变量必须使用标识符,即字母数字下划线,且不能以数字开头

  1. extern int d = 3, f = 5; // d 和 f 的声明与初始化

  2. int d = 3, f = 5; // 定义并初始化 d 和 f

  3. byte z = 22; // 定义并初始化 z

  4. char x = 'x'; // 变量 x 的值为 'x'

不带初始化的定义:带有静态存储持续时间的变量会被隐式初始化为 NULL(所有字节的值都是 0),其他所有变量的初始值是未定义的。

那么,在C语言运行的时候变量到底储存在内存的什么地方呢?首先我们需要知道,内存被分为栈(stack)堆(heap)变量是储存在栈上的,就像这样

根据代码的执行顺序,变量a首先被压入栈中,然后是变量b。出栈时,是b先出栈,然后是a,即先进后出。变量在程序执行完毕后会自动释放掉存储单元。

内存中栈有多大?而堆又有多大?   栈对于不同的机器都不相同,大约1M-2M。

堆原则上是没限制的,你的硬件有多大的存储空间就可以分配相应大小的堆,另外定义在堆中的需要程序员手动回收

当不同类型变量之间发生赋值的时候,会发生一些转换。分别有显式类型转换隐式类型转换

显式类型转换:float a = 15.2; int b = a; 这时会发生警告,所以,当在赋值的时候加上 int b = (int)a;
在运算过程当中:
float a = 3.33
Float b =4.44
Int c = (int)a+(int)b;   //对 a 和 b 都进行了强制类型转化
Int c = (int)a+b;         //只对前一个转换
Int c = (int)(a+b);    //对 a+b 进行转化
这样就是强制类型转换

5/2 = 2
5.0/2 == 5/2.0;
float b = 5/2;//2.0
float c = (float)5/2;//2.5
float d = (float)(5/2);//2.0
float e = 5/(float)2;//2.5
隐式类型转换:

双目运算中,低类型的数据直接转换为高类型数据,其中无符号整数类型高于有符号的整数类型,int 数据类型之下的运算转换成 int 类型处理。

如:

char 类型 short 类型的运算转换为 int 数据类型。
long 与 double 型数据运算,先将 long 型数据转换成 double 型,结果为double 型。
一个 float 型数据与一个浮点型的默认运算是 double 型,意味着两个 float数的运算可优先转换为 double 型,结果的类型也可以是 float 型。
例如:
float a = 15.2f;
float c = a+12.5;   //此时会弹出警告,从 float 到 double 会发生数据截断。

浮点数(关于float型变量在内存中的存储)

在 C 语言中有种类型叫做浮点类型:float(单精度)、double(双精度),int a = 10;内存会分配 4 个字节给变量 a。那如果定义一个变量 float b = 12.5f;内存如何来分配的呢?首先也占 4 个字节,但在内部是这样的:

对于符号位来说肯定是正数,那么符号位保存 0,接下来就是重点:将 12.5 转换为二进制是:1100.1,写成科学计数法 1.1001*2^3,在这里面,1001 属于尾数,3 属于指数。那只需要在指数部位存入 3,尾数部位存入 1001 就好了

指数部分怎么存?

首先指数可能为负数,如果 0.0023写成计数法,2.3*10^-3,说明也会出现负数的情况,那么,在指数的这 8 位,需不需要再次存放指数的符号位呢?答案是不需要。所以这里有一个办法:让指数加上 127 的值(二进制)存放在这 8 位里面。对于尾数,现在只有 4 位,1001。怎么填充这 23 位呢?填 0 怎么填?指数的取值范围:-127 - 128,如果除去指数为 0 和 1 那就是-126-127精度:尾数表示精度,尾数越多越精确有效。

大小端:

大端模式,是指数据的高字节保存在内存的低地址中,而数据的低字节保存在内存的高地址中,这样的存储模式有点儿类似于把数据当作字符串顺序处理:地址由小向大增加,而数据从高位往低位放;这和我们的阅读习惯一致。

小端模式,是指数据的高字节保存在内存的高地址中,而数据的低字节保存在内存的低地址中,这种存储模式将地址的高低和数据位权有效地结合起来,高地址部分权值高,低地址部分权值低。

位运算符

针对二进制
11: 0000 1011
13: 0000 1101
~11:1111 0100     //  ~ 按位取反
11&13:0000 1001  // &按为相与
11|13:0000 1111    // | 按位相或
11^13:0000 0110  // ^ 按位异或
11<<1:0001 0110 // << 左移  22  11乘以 2^1
11<<2:0010 1100 //  44 11乘以 2^2
11>>1:0000 0101 // >> 右移   5  11/2 = 5
11>>2:0000 0010 //  2 11/4 = 2
-1>>1:还是 -1

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值