目录

前文列表

程序编译流程与 GCC 编译器

C 语言编程 — 基本基本语法

C 语言编程 — 数据类型

变量与常量

C 中有两种类型的表达式:

  • 左值(lvalue):指向内存位置的表达式被称为左值(lvalue)表达式,即:命名标识符。左值可以出现在赋值号的左边或右边。
  • 右值(rvalue):指的是存储在内存中某些地址的数值,即:实际的数据值。右值是不能对其进行赋值的表达式,也就是说,右值可以出现在赋值号的右边,但不能出现在赋值号的左边。

变量和常量是左值,因此可以出现在赋值号的左边。数值型的字面值是右值,因此不能被赋值,不能出现在赋值号的左边。

变量

变量其实就是一个有名字的数据项。或者说,变量表示一个具有名字的,具有特定属性的存储空间。在程序运行过程中该存储空间内的数据值可以被改变。习惯上,变量名使用小写字母表示,而大写字母常用于字符常量或自定义数据类型名。

变量具有下列三个要素:

  1. 变量名:内存入口地址
  2. 数据类型:决定了内存空间的大小
  3. 数据值:储存在内存空间中的数值

变量的类型

变量名由字母、数字和下划线字符组成。它必须以字母或下划线开头,大小写敏感。有以下几种基本的变量类型:



此外,C 语言也允许定义各种其他类型的变量,比如枚举、指针、数组、结构、共用体等等。

变量的声明

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

若只是声明定义了变量的数据类型,但却没有为变量赋予数据值,则变量所分配的内存单元中还保留着自上一次内存单元存储的旧数据。

变量的声明有两种情况:

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

变量的定义

变量定义,就是告诉编译器在何处创建变量的存储,以及如何创建变量的存储。本质就是确定了内存地址的起始地址和内存空间大小。

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

int    i, j, k;
char c, ch;
float f, salary;
double d;

变量的初始化与赋值

同时完成变量的定义和初始化:把数值填充到内存空间。

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

变量的初始化本质就是与变量定义同时进行的第一次赋值,此外的都称之为赋值。

#include <stdio.h>

// 定义全局变量
int x;
int y; int addtwonum(){
// 声明使用全局变量
extern int x;
extern int y;
// 为全局变量进行赋值
x = 1;
y = 1;
return x + y;
} int main(){
int result;
result = addtwonum();
printf("result : %d", result); return 0;
}

常量

常量就像是常规的变量,常量是固定值,在程序执行期间不会改变,通常使用大写字母标识。

  • 整型常量:即整数
  • 浮点型常量:又称为实型常量,即小数,可使用小数或指数形式来表示
  • 字符型常量:即符号,用单引号括起来的一个字符,具有一般字符和转义字符两种类型
  • 字符串常量:即用双引号括起来的多个字符组成的字符序列
  • 符号常量:即对常量进行命名,所以字符常量即是常量名,使用 const 关键字或 #define 预处理器指令来定义

整型常量

整数常量可以是十进制、八进制或十六进制的常量,通过前缀来确定。整数常量也可以带一个后缀,后缀是 U 和 L 的组合,U 表示无符号整数(unsigned),L 表示长整数(long)。后缀可以是大写,也可以是小写,U 和 L 的顺序任意。

85         /* 十进制 */
0213 /* 八进制 */
0x4b /* 十六进制 */
30 /* 整数 */
30u /* 无符号整数 */
30l /* 长整数 */
30ul /* 无符号长整数 */

浮点型常量

浮点型常量,又称实型常量,具有以下两种表示方式:

  • 小数形式:带小数点的常数。例如:21.290000。
  • 指数形式(科学计数法):由数符尾数(整数或小数)、阶码标志(E 或 e)、阶符和整数阶码组成的常数。例如:2.129000e+001。

NOTE:

  • 浮点型常量默认为双精度 double 类型。
  • 若浮点型常量以 F 或 f 结尾,表示该浮点型常量为单精度 float 类型常量。
  • 若浮点型常量以 l 或 L 结尾,表示该浮点型常量为 long double 类型常量。
3.14159       /* 合法的 */
314159E-5L /* 合法的 */
510E /* 非法的:不完整的指数 */
210f /* 非法的:没有小数或指数 */
.e55 /* 非法的:缺少整数或分数 */

字符型场景

字符型(Char)常量:用单引号括起来,具有两种类型:

  • 一般字符常量:一个用单引号 ’ ’ 括起来的字符。
  • 转义字符常量:一个用单引号 ’ ’ 括起的,并以反斜杠 ‘’ 开头的字符,用于表示具有特殊功能的字符。

字符型常量占用 1Byte 内存空间,以 ASCII 码形式(即整型)存储。 因此,字符型数据对象和整型数据对象是可相互转换的。

下表列出了转义序列表:

字符串常量

字符串(String)常量:一个用双引号 " " 括起来的字符串,可以保存多个字符(e.g. “abc”)。

字符串常量中的字符序列在内存中连续存储,并在最后面加上转义字符 ‘\0’ 作为字符串结束标志,字符 ‘\0’ 占用 1Byte 内存空间。 例如:字符串 “HELLO” 在内存实际占据 6Bytes,实际字符存放顺序为 ‘H’、‘E’、‘L’、‘L’、‘O’、’\0’。

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

"hello, dear"

"hello, \
dear" "hello, " "d" "ear"

符号常量

使用符号来作为常量的标识,所以也叫常量名。

符号常量具有两种定义方式:

  1. 使用 #define 预处理器定指令义常量的形式,不需要声明常量的数据类型#define 符号常量名 常量表达式;
#include <stdio.h>

#define LENGTH 10
#define WIDTH 5
#define NEWLINE '\n' int main()
{ int area; area = LENGTH * WIDTH;
printf("value of area : %d", area);
printf("%c", NEWLINE); return 0;
}
  1. 使用 const 关键字声明指定类型的常量:const 数据类型 符号常量名 = 常量表达式;
#include <stdio.h>

int main()
{
const int LENGTH = 10;
const int WIDTH = 5;
const char NEWLINE = '\n';
int area; area = LENGTH * WIDTH;
printf("value of area : %d", area);
printf("%c", NEWLINE); return 0;
}

NOTE

  • 使用 const 方式定义符号常量时,必须初始化符号常量
  • 在程序运行过程中,不能修改符号常量的数据值
  • 符号常量名一般用大写字母表示
  • 符号常量定义中的常量表达式不能含有变量或函数

作用域

所谓作用域(Scope),就是变量的有效范围。C 语言中所有的变量都有自己的作用域,决定变量作用域的是变量的定义位置。

  • 局部变量(Local Variable):定义在函数内部的变量称为局部变量,包括函数形参变量。实参给形参传值的过程也就是给局部变量赋值的过程。
  • 全局变量(Global Variable):它的作用域默认是整个程序,也就是所有的源文件,包括 .c 和 .h 文件。

注:局部变量和全局变量的名称可以相同,但是在函数内,如果两个名字相同,会优先使用局部变量值,全局变量不会被使用。

全局变量与局部变量在内存中的区别:

  • 全局变量保存在内存的全局存储区中,占用静态的存储单元;
  • 局部变量保存在栈中,只有在所在函数被调用时才动态地为变量分配存储单元。
  • 当局部变量被定义时,系统不会对其初始化,您必须自行对其初始化。定义全局变量时,系统会自动对其初始化。

注:正确地初始化变量是一个良好的编程习惯。

如果需要在一个源文件中引用另外一个源文件中定义的变量,我们只需在引用的源文件中将变量加上 extern 关键字的声明即可。如下例:

  • addtwonum.c
#include <stdio.h>

extern int x;
extern int y; int addtwonum(){
return x + y;
}
  • main.c
#include <stdio.h>

int x=1;
int y=1; int addtwonum(); int main(){
int result;
result = addtwonum();
printf("result : %d", result); return 0;
}

运行

$ gcc -Wall main.c addtwonum.c -o main

$ ./main
result : 2

注意,因为 C 语言代码是从前往后依次执行的,所以全局变量通常位于源文件的顶部。

int a, b;  //全局变量
void func1(){
//TODO:
}
float x,y; //全局变量
int func2(){
//TODO:
}
int main(){
//TODO:
return 0;
}

a、b、x、y 都是在函数外部定义的全局变量。由于 x、y 定义在函数 func1() 之后,所以在 func1() 内无效;而 a、b 定义在源程序的开头,所以在 func1()、func2() 和 main() 内都有效。

存储类

存储类定义了 C 程序中的变量/函数的作用域和生命周期,通过特殊的修饰符(关键字)来进行修饰不同的变量/函数,使得他们具有灵活的作用域。下面列出 C 程序中可用的存储类:

  • auto
  • register
  • static
  • extern

auto 修饰符

auto 存储类是所有局部变量默认的存储类。auto 只能用在函数内,即 auto 只能用于修饰局部变量。

下述实例定义了两个具有相同存储类的变量:

{
int mount;
auto int month;
}

register 修饰符

register 存储类用于定义存储在寄存器中而不是内存中的局部变量。这意味着变量的最大 Size 等于寄存器的 Size,且不能对它应用一元运算符 ‘&’ (因为它没有内存空间)。

寄存器只用于需要快速访问的变量,比如:计数器。还应注意的是,使用了 register 修饰符进行修复并不意味着变量将被存储在寄存器中,它意味着变量可能存储在寄存器中,这取决于硬件和实现的限制。

{
register int miles;
}

static 修饰符

被 static 修饰的变量和常量被称为 静态变量 或 静态常量。

  • 用于修饰局部变量时:编译器在程序的生命周期内保持局部变量的存在,不会在每次进入和离开函数的时候对局部变量进行重新的创建和销毁(重新赋值)。因此,使用 static 修饰局部变量可以在函数调用之间保持住局部变量的值不被重置。

  • 用于修饰全局变量时:会使变量的作用域限制在声明它的源文件内,而不再是整个程序。

#include <stdio.h>

/* 函数声明 */
void func1(void); static int count=10; /* 全局变量 - static 是默认的 */ int main()
{
while (count--) {
func1();
}
return 0;
} void func1(void)
{
/* 'thingy' 是 'func1' 的局部变量 - 只初始化一次
* 每次调用函数 'func1' 'thingy' 值不会被重置。
*/
static int thingy=5;
thingy++;
printf(" thingy 为 %d , count 为 %d\n", thingy, count);
}

运行:

$ ./main
thingy 6, count 9
thingy 7, count 8
thingy 8, count 7
thingy 9, count 6
thingy 10, count 5
thingy 11, count 4
thingy 12, count 3
thingy 13, count 2
thingy 14, count 1
thingy 15, count 0

可见,静态变量 thingy 不会在每次函数调用时重置。

extern 修饰符

extern 存储类用于提供一个全局变量/函数的引用。全局变量/函数的作用域是整个程序,当你在一个源文件中想引用另外一些源文件中定义的全局变量/函数时,你可以在该源文件中使用 extern 修饰符,修饰一个全局变量/函数,而且不需要进行初始化(因为该全局变量实际上在另一个源文件中已经完成了初始化)。

简而言之,extern 修饰符就是用与在一个文件中,对另外一个完全中的全局变量或函数进行声明(但不定义),向编译器保证该变量/函数的存在(即便变量/函数的定义并不在本文件中)。

  • main.c
#include <stdio.h>

int count ;
extern void write_extern(); int main()
{
count = 5;
write_extern();
}
  • support.c
#include <stdio.h>

extern int count;

void write_extern(void)
{
printf("count is %d\n", count);
}

C 语言编程 — 变量与常量的更多相关文章

  1. Go语言 2 变量、常量和数据类型

    文章由作者马志国在博客园的原创,若转载请于明显处标记出处:http://www.cnblogs.com/mazg/ Go学习群:415660935 2.1 变量 变量是对一块内存空间的命名,程序可以通 ...

  2. Go语言的变量和常量(三)

    我想吐槽下网上的很多所谓的“零基础教程”,因为那根本不算零基础.就拿语言教程来说,一上来就说怎么定义变量的怎么算零基础呢?零基础应该是先告诉你啥叫变量. 所以我从不起零基础的标题.我这也不是教程,只是 ...

  3. C语言之变量与常量的介绍

    一 标示符 标识符:可以理解为是变量名.名字常量表示法的常量名,但是不仅限于这两个 命名规范: 1.起名要有意义,基本要做到一看名字就知道是用来干嘛的(要求你遵守,但不会报错,希望能够养成这样的好习惯 ...

  4. go语言学习——变量、常量、循环、条件、switch、数组和切片

    1.变量 package main import "fmt" func main() { 个或者多个变量. var a string = "initial" f ...

  5. c语言的变量,常量及作用域等

    1.const定义常量 在C语言中,const可以用来定义的一个常量,在变量名前加上const即可. int const a: 定义了一个a的整数常量,且a的值不能被修改.如果要修改a的值,有以下两种 ...

  6. C语言基础学习基本数据类型-变量和常量

    变量和常量 什么是变量和常量?有些数据在程序运行前就预先设定,并在运行过程中不发生变化,称之为常量:有些数据在程序运行中可能发生变化或被赋值,称之为变量. 使用变量前必须先声明一个变量.变量定义的语法 ...

  7. Go语言基础之变量和常量

    Go语言基础之变量和常量 变量和常量是编程中必不可少的部分,也是很好理解的一部分. 标识符与关键字 标识符 在编程语言中标识符就是程序员定义的具有特殊意义的词,比如变量名.常量名.函数名等等. Go语 ...

  8. Go 语言基础——变量常量的定义

    go语言不支持隐式类型转换,别名和原有类型也不能进行隐式类型转换 go语言不支持隐式转换 变量 变量声明 var v1 int var v2 string var v3 [10]int // 数组 v ...

  9. 1.2 Go语言基础之变量和常量

    变量和常量是编程中必不可少的部分,也是很好理解的一部分. 一.标识符与关键字 1.1 标识符 在编程语言中标识符就是程序员定义的具有特殊意义的词,比如变量名.常量名.函数名等等. Go语言中标识符由字 ...

  10. 【Go语言系列】2.3、Go语言基本程序结构:变量及常量

    1.什么变量 变量来源于数学,从根本上说,变量相当于是对一块数据存储空间的命名,程序可以通过定义一个变量来申请一块数据存储空间,之后可以通过引用变量名来使用这块存储空间. 1.1变量声明 Go 语言变 ...

随机推荐

  1. Python - 字典1

    字典用于存储键值对形式的数据.字典是一个有序.可更改的集合,不允许重复.从 Python 3.7 版本开始,字典是有序的.在 Python 3.6 及更早版本中,字典是无序的.字典用花括号编写,具有键 ...

  2. Django集成layui 的 layedit 之图片上传接口

    # a.html <!DOCTYPE html> <html lang="en"> <head> <meta charset=" ...

  3. 在Mac系统上使用Qt调用摄像头不出图解决方法

    需求:在Mac系统上,调用摄像头,实现旋转.缩放.处理视频帧等功能 问题:使用获取视频帧的方法,在Mac上调不起来摄像头 解决方法: 将视频窗口(QVideoWidget)和视频帧(QVideoFra ...

  4. 第十九篇:Django ORM外键关联关系

    一.一对多的创建 二.一对多跨表操作 三.创建多对多 四.Ajax处识 五.模板继承与导入 六.自定义分页

  5. JackSon反序列化通杀

    前言 Springboot一般都会自带JackSon这个依赖包,JackSon跟Fastjson有相同的功效 简单复现 package com.example.jakeson.demo; import ...

  6. Leetcode-栈的压入弹出序列

    /* 输入:pushed = [1,2,3,4,5], popped = [4,5,3,2,1] 输出:true 解释:我们可以按以下顺序执行: push(1), push(2), push(3), ...

  7. 高并发场景QPS等专业指标揭秘大全与调优实战

    高并发场景QPS等专业指标揭秘大全与调优实战 最近经常有小伙伴问及高并发场景下QPS的一些问题,特意结合项目经验和网上技术贴做了一些整理和归纳,供大家参考交流. 一.一直再说高并发,多少QPS才算高并 ...

  8. pytorch,numpy两种方法实现nms类间+类内

    类间:也就是不同类之间也进行nms 类内:就是只把同类的bboxes进行nms numpy实现 nms类间+类内: import numpy as np # 类间nms def nms(bboxes, ...

  9. leetcode:1381. 设计一个支持增量操作的栈

    1381. 设计一个支持增量操作的栈 请你设计一个支持下述操作的栈. 实现自定义栈类 CustomStack : CustomStack(int maxSize):用 maxSize 初始化对象,ma ...

  10. GaussDB(DWS)基于Flink的实时数仓构建

    本文分享自华为云社区<GaussDB(DWS)基于Flink的实时数仓构建>,作者:胡辣汤. 大数据时代,厂商对实时数据分析的诉求越来越强烈,数据分析时效从T+1时效趋向于T+0时效,为了 ...