C基础篇 数据类型,变量和常量

 


变量及赋值#

变量就是可以变化的量,而每个变量都会有一个名字(标识符)。变量占据内存中一定的存储单元。使用变量之前必须先定义变量,要区分变量名变量值是两个不同的概念。

1
变量定义的一般形式为:数据类型 变量名;<br>多个类型相同的变量:数据类型 变量名, 变量名, 变量名...;

运用实例#

1
2
3
4
5
6
7
8
9
10
11
12
#include<stdio.h>
int main()
{
    int num; //定义了一个整数变量,变量名字叫num
    num=99;  //给num变量赋值为99
    int a,b,c; //同时声明多个变量,然后分别赋值
    a=5;
    b=2;
    c=0;
    printf("%d\n",num); //打印整型变量num
    return 0;
}

注意:在定义中不允许连续赋值,如int a=b=c=5;是不合法的,和python不同

变量的赋值两种方式

1
2
先声明再赋值
声明的同时赋值

基本数据类型#

C语言中,数据类型可分为

1
2
3
4
基本数据类型
构造数据类型
指针类型
空类型四大类
数据类型分类

最常用的整型, 实型与字符型(char,int,float,double):

整型,实型,字符型

整型数据是指不带小数的数字

整型

注:

1
2
3
4
int short int long int是根据编译环境的不同,所取范围不同。
而其中short int和long int至少是表中所写范围, 但是int在表中是以16位编译环境写的取值范围。
另外 c语言int的取值范围在于他占用的字节数 ,不同的编译器,规定是不一样。
ANSI标准定义int是占2个字节,TC是按ANSI标准的,它的int是占2个字节的。但是在VC里,一个int是占4个字节的

浮点数据是指带小数的数字

1
生活中有很多信息适合使用浮点型数据来表示,比如:人的体重(单位:公斤)、商品价格、圆周率等等

因为精度的不同又分为3种

浮点型

注:C语言中不存在字符串变量,字符串只能存在字符数组中,这个后面会讲。

类型描述
char 通常是一个字节(八位)。这是一个整数类型。
int 对机器而言,整数的最自然的大小。二进制反码形式存储
float

单精度浮点值。单精度是这样的格式,1位符号,8位指数,23位小数。

double

双精度浮点值。双精度是1位符号,11位指数,52位小数。

void 表示类型的缺失。

C 语言也允许定义各种其他类型的变量,比如枚举、指针、数组、结构、共用体等等,这将会在后续的章节中进行讲解

格式化输出语句#

格式化输出语句,也可以说是占位输出,是将各种类型的数据按照格式化后的类型及指定的位置从计算机上显示。

其格式为:printf("输出格式符",输出项); c语言常用格式化符

当输出语句中包含普通字符时,可以采用一下格式:

1
printf("普通字符 输出格式符", 输出项); 

运用实例

注意:格式符的个数要与变量、常量或者表达式的个数一一对应

不可改变的常量#

在程序执行过程中,值不发生改变的量称为常量

C语言的常量可以分为直接常量和符号常量

1
2
3
4
5
直接常量也称为字面量,是可以直接拿来使用,无需说明的量,比如
整型常量:13、0、-13;
实型常量:13.33、-24.4;
字符常量:‘a’、‘M’
字符串常量:”I love you!”

在C语言中,可以用一个标识符来表示一个常量,称之为符号常量。符号常量在使用之前必须先定义,其一般形式为

1
2
3
4
5
6
7
8
9
#define 标识符 常量值 <br>
#include <stdio.h>
#define POCKETMONEY 10    //定义常量及常量值
int main()
{
    // POCKETMONEY = 12;  //小明私自增加零花钱对吗?
    printf("小明今天又得到%d元零花钱\n", POCKETMONEY);
    return 0; 
}

符号常量不可以被改变

自动类型转换#

数据类型存在自动转换的情况.
自动转换发生在不同数据类型运算时,在编译的时候自动完成

自动转换

char类型数据转换为int类型数据遵循ASCII码中的对应值.

注意:

1
2
字节小的可以向字节大的自动转换,但字节大的不能向字节小的自动转换
char可以转换为int,int可以转换为double,char可以转换为double。但是不可以反向

强制类型转换#

强制类型转换是通过定义类型转换运算来实现的。其一般形式为:

1
(数据类型) (表达式)

其作用是把表达式的运算结果强制转换成类型说明符所表示的类型

在使用强制转换时应注意以下问题

1
2
3
数据类型和表达式都必须加括号, 如把(int)(x/2+y)写成(int)x/2+y则成了把x转换成int型之后再除2再与y相加了
转换后不会改变原数据的类型及变量值,只在本次运算中临时性转换
强制转换后的运算结果不遵循四舍五入原则

C 中的变量定义#

变量定义就是告诉编译器在何处创建变量的存储,以及如何创建变量的存储。变量定义指定一个数据类型,并包含了该类型的一个或多个变量的列表,如下

1
type variable_list;

在这里,type 必须是一个有效的 C 数据类型,可以是 char、w_char、int、float、double 或任何用户自定义的对象,variable_list 可以由一个或多个标识符名称组成,多个标识符之间用逗号分隔。下面列出几个有效的声明

1
2
3
4
int    i, j, k;
char   c, ch;
float  f, salary;
double d;

int  i, j, k; 声明并定义了变量 i、j 和 k,这指示编译器创建类型为 int 的名为 i、j、k 的变量。

变量可以在声明的时候被初始化(指定一个初始值)。初始化器由一个等号,后跟一个常量表达式组成,如下

1
type variable_name = value;

下面列举几个实例

1
2
3
4
extern int d = 3, f = 5;    // d 和 f 的声明与初始化
int d = 3, f = 5;           // 定义并初始化 d 和 f
byte z = 22;                // 定义并初始化 z
char x = 'x';               // 变量 x 的值为 'x'

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

C 中的变量声明#

变量声明向编译器保证变量以指定的类型和名称存在,这样编译器在不需要知道变量完整细节的情况下也能继续进一步的编译。变量声明只在编译时有它的意义,在程序连接时编译器需要实际的变量声明。

变量的声明有两种情况

1
2
3
4
5
1、一种是需要建立存储空间的。例如:int a 在声明的时候就已经建立了存储空间。
2、另一种是不需要建立存储空间的,通过使用extern关键字声明变量名而不定义它。 例如:extern int a 其中变量 a 可以在别的文件中定义的。
 
除非有extern关键字,否则都是变量的定义extern int i; //声明,不是定义
int i; //声明,也是定义

C 中的左值(Lvalues)和右值(Rvalues)#

C 中有两种类型的表达式

1
2
左值(lvalue):指向内存位置的表达式被称为左值(lvalue)表达式。左值可以出现在赋值号的左边或右边
右值(rvalue):术语右值(rvalue)指的是存储在内存中某些地址的数值。右值是不能对其进行赋值的表达式,也就是说,右值可以出现在赋值号的右边,但不能出现在赋值号的左边

变量是左值,因此可以出现在赋值号的左边。数值型的字面值是右值,因此不能被赋值,不能出现在赋值号的左边。下面是一个有效的语句

1
int g = 20;

但是下面这个就不是一个有效的语句,会生成编译时错误

1
10 = 20;

常量是固定值,在程序执行期间不会改变。这些固定的值,又叫做字面量

常量可以是任何的基本数据类型,比如整数常量、浮点常量、字符常量,或字符串字面值,也有枚举常量。

常量就像是常规的变量,只不过常量的值在定义后不能进行修改

整数常量#

整数常量可以是十进制、八进制或十六进制的常量。前缀指定基数:0x 或 0X 表示十六进制,0 表示八进制,不带前缀则默认表示十进制。

整数常量也可以带一个后缀,后缀是 U 和 L 的组合,U 表示无符号整数(unsigned),L 表示长整数(long)。后缀可以是大写,也可以是小写,U 和 L 的顺序任意。

下面列举几个整数常量的实例:

1
2
3
4
5
212         /* 合法的 */
215u        /* 合法的 */
0xFeeL      /* 合法的 */
078         /* 非法的:8 不是八进制的数字 */
032UU       /* 非法的:不能重复后缀 */

以下是各种类型的整数常量的实例:

1
2
3
4
5
6
7
85         /* 十进制 */
0213       /* 八进制 */
0x4b       /* 十六进制 */
30         /* 整数 */
30u        /* 无符号整数 */
30l        /* 长整数 */
30ul       /* 无符号长整数 */

浮点常量#

浮点常量由整数部分、小数点、小数部分和指数部分组成。您可以使用小数形式或者指数形式来表示浮点常量。

当使用小数形式表示时,必须包含整数部分、小数部分,或同时包含两者。当使用指数形式表示时, 必须包含小数点、指数,或同时包含两者。带符号的指数是用 e 或 E 引入的。

下面列举几个浮点常量的实例:

字符常量#

字符常量是括在单引号中,例如,'x' 可以存储在 char 类型的简单变量中。

字符常量可以是一个普通的字符(例如 'x')、一个转义序列(例如 '\t'),或一个通用的字符(例如 '\u02C0')。

在 C 中,有一些特定的字符,当它们前面有反斜杠时,它们就具有特殊的含义,被用来表示如换行符(\n)或制表符(\t)等。下表列出了一些这样的转义序列码:

转义序列含义
\\ \ 字符
\' ' 字符
\" " 字符
\? ? 字符
\a 警报铃声
\b 退格键
\f 换页符
\n 换行符
\r 回车
\t 水平制表符
\v 垂直制表符
\ooo 一到三位的八进制数
\xhh . . . 一个或多个数字的十六进制数

实例#

字符串常量#

字符串字面值或常量是括在双引号 "" 中的。一个字符串包含类似于字符常量的字符:普通的字符、转义序列和通用的字符

您可以使用空格做分隔符,把一个很长的字符串常量进行分行

下面的实例显示了一些字符串常量,下面这三种形式所显示的字符串是相同的

1
2
3
4
5
6
"hello, dear"
 
"hello, \
dear"
 
"hello, " "d" "ear"

定义常量#

在 C 中,有两种简单的定义常量的方式

1
2
使用 #define 预处理器
使用 const 关键字

#define 预处理器#

下面是使用 #define 预处理器定义常量的形式

1
#define identifier value

实例#

const 关键字#

您可以使用 const 前缀声明指定类型的常量,如下

1
const type variable = value;

实例#

请注意,把常量定义为大写字母形式,是一个很好的编程规范

整数的取值范围以及数值溢出#

关于数据溢出,当类型的运算超出类型的取值范围,便会出现数据溢出。数据溢出得到的结果往往不是我们想要的。下面继续以byte类型为例来进行讨论。

在C语言中使用中文字符#

待补充

C语言到底使用什么编码#

表达式(Expression)和语句(Statement)#

C语言自增(++)和自减(--)#

变量的定义位置以及初始值#

在c语言中变量的定义必须放在所有执行语句的前面,而c++中则是任意的 

顺着这个思路想了一下,为什么C语言的全局变量(global)就算不赋值会被自动初始化位默认值,但是局部变量(local)不会呢? 学习了一下C语言的内存布局结构,然后自己验证了一下然后明白了这个原因。

首先我们得知道C语言的内存布局结构

全局变量是存放在data段内存的。data段分为uninitialized data(bss)段和initalized data,未初始化的变量是放在bss段的,这部分内存存放的变量是会被自动初始化的(这是C语言的特性)局部变量是存放在stack段的。这部分内存是被runtime时期动态分配的。(其实局部变量在代码编译之后就是一个地址,接下来会演示出来)

一般变量看不出什么区别,对于静态变量就很明显了,如:
int func(){static int a = 10; //初始化static int b;b = 10; //赋值a++;b++;printf("%d\n", a); //第一次调用函数func,a 的值为 11,第二次调用时为 12,……printf("%d\n", b); //第一次调用函数func,b 的值为 11,第二次调用时为 11,……}从上例可以看出,静态变量只初始化一次,所以 a 的值会随调用的次数递增;而 b 由于重新赋值,所以他的值始终是 11。

运算符的优先级和结合性#

C语言的运算符和结合性主要还是要记住一个表,不明白的时候我们就翻看一下。C语言的运算符众多,具有不同的优先级和结合性,将它们全部列了出来,方便大家对比和记忆:

注:同一优先级的运算符,运算次序由结合方向所决定。上面的表无需死记硬背,很多运算符的规则和数学中是相同的,用得多,看得多自然就记得了。如果你是在记不住,可以使用( )。

从一个例子入手讲解

请看下面的代码:

#include<stdio.h>intmain(){int a =16, b =4, c =2;int d = a + b * c;int e = a / b * c;printf("d=%d, e=%d\n", d, e);return0;}运行结果:d=24, e=8

1) 对于表达式a + b * c,如果按照数学规则推导,应该先计算乘法,再计算加法;b * c的结果为 8,a + 8的结果为 24,所以 d 最终的值也是 24。从运行结果可以看出,我们的推论得到了证实,C语言也是先计算乘法再计算加法,和数学中的规则一样。先计算乘法后计算加法,说明乘法运算符的优先级比加法运算符的优先级高。所谓优先级,就是当多个运算符出现在同一个表达式中时,先执行哪个运算符。C语言有几十种运算符,被分成十几个级别,有的运算符优先级不同,有的运算符优先级相同,C语言运算符很多,大家可以查看上面的表格,有C语言书籍的也可以查看后面的附录,一般也是有的。一下子记住所有运算符的优先级并不容易,还好C语言中大部分运算符的优先级和数学中是一样的,大家在以后的编程过程中也会逐渐熟悉起来。如果实在搞不清,可以加括号,就像下面这样:

int d = a + (b * c);括号的优先级是最高的,括号中的表达式会优先执行,这样各个运算符的执行顺序就一目了然了。2) 对于表达式a / b * c,除法和乘法的优先级是相同的,这个时候到底该先执行哪一个呢?按照数学规则应该从左到右,先计算除法,在计算乘法;a / b的结果是 4,4 * c的结果是 8,所以 e 最终的值也是 8。这个推论也从运行结果中得到了证实,C语言的规则和数学的规则是一样的。当乘法和除法的优先级相同时,编译器很明显知道先执行除法,再执行乘法,这是根据运算符的结合性来判定的。所谓结合性,就是当一个表达式中出现多个优先级相同的运算符时,先执行哪个运算符:先执行左边的叫左结合性,先执行右边的叫右结合性。/和*的优先级相同,又都具有左结合性,所以先执行左边的除法,再执行右边的乘法。3) 像 +、-、*、/ 这样的运算符,它的两边都有要计算的数据,每份这样的数据都称作一个操作数,一个运算符需要 n 个操作数就称为 n 目运算符。例如:

+、-、*、/、= 是双目运算符;++、-- 是单目运算符;? : 是三目运算符(这是C语言里唯一的一个三目元算符,这个就必须强行记住了呀)。一些容易出错的优先级问题

 

上表中,优先级同为1 的几种运算符如果同时出现,那怎么确定表达式的优先级呢?这是很多初学者迷糊的地方。下表就整理了这些容易出错的情况:

放大图片仔细看喔

这些容易出错的情况,好好在编译器上调试调试,这样印象会深一些。一定要多调试,光靠看代码,水平是很难提上来的。调试代码才是最长水平的。

当一个表达式中出现多个运算符时,C语言会先比较各个运算符的优先级,按照优先级从高到低的顺序依次执行;当遇到优先级相同的运算符时,再根据结合性决定先执行哪个运算符:如果是左结合性就先执行左边的运算符,如果是右结合性就先执行右边的运算符。

posted @   鲸鱼的海老大  阅读(20)  评论(0编辑  收藏  举报
编辑推荐:
· 10年+ .NET Coder 心语,封装的思维:从隐藏、稳定开始理解其本质意义
· .NET Core 中如何实现缓存的预热?
· 从 HTTP 原因短语缺失研究 HTTP/2 和 HTTP/3 的设计差异
· AI与.NET技术实操系列:向量存储与相似性搜索在 .NET 中的实现
· 基于Microsoft.Extensions.AI核心库实现RAG应用
阅读排行:
· 10年+ .NET Coder 心语 ── 封装的思维:从隐藏、稳定开始理解其本质意义
· 地球OL攻略 —— 某应届生求职总结
· 提示词工程——AI应用必不可少的技术
· Open-Sora 2.0 重磅开源!
· 周边上新:园子的第一款马克杯温暖上架
点击右上角即可分享
微信分享提示
CONTENTS