其值不能被改变的量成为常量。C语言中,常量有不同的类型,如整型常量(不含小数点)、实型常量(通常用带小数点的数表示)、字符型常量(用单引号括起来的一个字符)、字符串常量(用双引号括起来的若干字符的字符序列)和符号常量(用标识符即符号来表示)等。
C语言中有以下两种方法定义符号常量:
变量是指在程序运行过程中其值可以被改变的量,定义变量的一般形式为:
· 类型名 变量名1,变量名2,…,变量名n;
int a, b, c; char d, e, f; long g, h, i;
【注意】C语言中要求所有用到的变量作强制定义,也就是**“先定义,后使用”**,目的如下:
①凡未被事先定义的,系统不把它认作变量名。例如,声明部分有以下语句:int student;
而在执行语句中错写成stadent=30; 在编译时检查出stadent未经定义,不作变量名,因此输出“Undefined symbol ‘stadent’ in function main” (main函数中未定义符号stadent)的信息
②每一个变量被指定为一个确定类型,在编译时就能为其分配相应的存储单元
③指定每一个变量属于一个类型,这就便于在编译时据此检查在程序中要求对该变量进行的运算是否合法
整型常量的3中表示形式如下:
①十进制数表示形式:如23、0、-16
②八进制数表示形式:以0开头是八进制数,如023,即八进制数的23(相当于十进制数的19)
③十六进制数表示形式:以0x开头作为十六进制数,如0x23,即十六进制数23(相当于十进制数的25)
整型变量的基本类型符为 int 。可以根据数值的范围将变量定义为基本整形、短整型或长整型。因此有以下3种整型变量
①基本整型,以 int 表示。
②短整型,以 short [int] 表示。
③长整型,以 long [int] 表示。
· 若在上述3中类型前再加上无符号整形标记 unsigned,则只能用来存储无符号整数,即在存储单元中的全部二进制位都用来存放数据本身,而没有符号位,也即不能存放负数。于是又有下列3中类型的整型变量
①无符号基本整型,以 unsigned [int] 表示。
②无符号短整型,以 unsigned short [int] 表示。
③无符号长整形,以 unsigned long [int] 表示。
【补充】
①[int] 是可有可无的。
②一个无符号整型变量刚好是其有符号数表示范围的上届与下届绝对值之和
如 signed [int] 可表示 -231-231-1;unsigned [int] 可表示 0~232-1
【注意】
①在一个整型常量后加一个字母u或U,则认为是 unsigned int 型,如123u。
②在一个整型常量后加一个字母l或L,则认为是 long int 型,如0L、123L。
在C语言中实型常量又称实数或浮点数,有如下两种表现形式:
(1)十进制形式。它由整数、小数点和小数3部分组成。当整数部分为0或小数部分为0时都可省略,但小数点不能省略。如,3.14、10.8、123.、.12、0.0等都是十进制数的表示形式,但该种表示形式不适合表示太小或太大的数。
(2)指数形式。它由尾数、大写字母E(或小写字母e)、整数指数3部分组成,适合表示比较小或比较大的数。字符E前必须有数字,且E后的指数必须为整数。如,3.0E+5或3.0e+5都表示3.0×105,1.23E-2表示0.0123。
实型变量又称浮点型变量,按能够表示数的精度又分为单精度(float 型)、双精度(double 型)和长精度(long double 型)3种
C语言中把用一对单引号括起来的单个字符称为字符常量。如,‘a’、‘A’、‘1’等。一个字符常量的值是该字符集中对应的编码值,如ASCⅡ字符集中,字符常量’0’-'9’的ASCⅡ编码值是48-57,显然‘0’和数字0是不同的。
C语言中还有一种特殊形式的字符常量,即转义字符常量。转义字符常量以反斜杠 “\” 开头,其后面跟一个特定的字符就转变为另外一种含义。常用的以 “\” 开头的特殊字符如下所示:
①\n------功能:换行,将当前位置移到下一行开头
②\t ------功能:水平制表符(TAB)
③\b------功能:退格,将当前位置移到前一列
④\r ------功能:回车,将当前位置移到本行开头
⑤\f ------功能:换页,将当前位置移到下页开头
⑥\ \ -----功能:代表一个反斜杠字符 “\”
⑦\ '------功能:代表一个单引号字符
⑧\‘’------功能:代表一个双引号字符
⑨\ddd–功能:ddd表示1~3个八进制的数字。如\130–>X
⑩\xdd–功能:dd表示2个十六进制的数字。如\x30–>0
【注意】: d代表要放的数字
int main() { printf("%c\n", '\130');//输出:X(X的ASCⅡ码值是88) printf("%c\n", '\101');//输出:A(A的ASCⅡ码值是65) printf("%c\n", '\x30');//输出:0(0的ASCⅡ码值是48) printf("%d\n", strlen("c:\test\128\test.c"));//14 return 0; }
字符变量是用来存放字符常量的,并且只能放一个字符,而不是一个字符串。它的关键字类型为 char ,占用1字节的内存单元。例如:
char c1,c2; /定义两个字符变量c1,c2/
c1 = ‘a’; c2 = ‘b’; /给字符变量赋值/
将一个字符常量存储到一个字符变量中,实际上是将该字符的ASCⅡ码值(无符号整数)存储到内存单元中
(1)字符串常量的定义
字符串常量是用一对双引号括起来的字符序列,即一串字符。字符串中字符的个数称为字符串的长度。长度为0的字符串称为空串,表示为“”。
如果反斜杠和双引号作为字符串的有效字符,则必须使用转义字符
(2)字符串的存储
在存储字符串常量时,由系统在字符串的末尾自动加一个 ‘\0’ 作为字符串的结束标志。如,定义一个char arr[] = “CHINA” 该字符串实际占用内存空间是6个字节,监视内容如下。
- arr 0x00d6f9e4 "\x1" char[6] [0] 1 '\x1' char [1] 0 '\0' char [2] 0 '\0' char [3] 0 '\0' char [4] 1 '\x1' char [5] 0 '\0' char
【注意】例:
char arr1[] = "abc";//当[]内不给初始值系统会默认按照右值进行分配空间 char arr2[] = {'a', 'b', 'c'}; //打印字符串 printf("%s\n", arr1);//输出:abc printf("%s\n", arr2);//输出:abc烫烫烫烫蘟bc
(3)求字符串长度—— strlen() 函数
使用该函数时需要引用的头文件:
#include <string.h>
函数的使用:
int main() { char arr1[] = "abc";//当[]内不给初始值系统会默认按照右值进行分配空间 char arr2[] = {'a', 'b', 'c', '\0'}; char arr3[] = {'a', 'b', 'c',}; //求字符串的长度 int len = strlen("abcd");//string length printf("%d\n", len);//3 printf("%d\n", strlen(arr1));//3 printf("%d\n", strlen(arr2));//3 printf("%d\n", strlen(arr3));//15,随机值,并提示没有结束标志 return 0; }
#include <stdio.h> int global = 2022;//全局变量 int main() { int local = 2021;//局部变量 int gloabl = 2020;//局部变量 printf("%d\n", gloabl);//结果为2022 return 0; }
【结论】:当全局变量和局部变量同名的时候,局部变量优先使用
引例:
#include <stdio.h> int main() { int a = 10; printf("%d\n", a);//a可用 return 0; }
【成功运行】
#include <stdio.h> int main() { { int a = 10; } printf("%d\n", a);//a不可用 return 0; }
【错误警告】:“a”:未声明的标识符
#include <stdio.h> int g_val = 2022;//全局变量 int main() { printf("1:%d\n", g_val);//可用 { printf("2:%d\n", g_val);//可用 int a = 10; printf("%d\n", a);//a不可用 } printf("3:%d\n", g_val);//可用 return 0; }
【成功运行】
【结论】
一个变量的生命周期:变量的创建和销毁之间的时间段
引例:
int main() { { int a = 10;//局部变量 printf("%d\n", a); } //进入局部范围生命开始,出局部范围生命结束 printf("%d\n", a); return 0; }
【结论】
3.14; 10; 'a'; "avswv";
const int num = 10;//num就是常变量-具有常属性,即不能被改变的属性
【结论】被const修饰的变量,虽然具有常属性,但本质上仍然是变量
#define MAXSIZE 10000 int main() { //MAXSIZE = 200;//error int n = MAXSIZE; printf("n = %d\n", n);//输出:10000 return 0; }
【结论】 被 #define 定义的常量是不可被修改的。#define可也在括号内定义
enum Sex { //这种枚举类型的变量的未来可能取值 MELE = 3,//赋初值 FEMALE, SECRET, };//枚举常量 int main() { //MELE = 7;//error enum Sex s = MELE; printf("%d\n", MELE);//输出:3 printf("%d\n", FEMALE);//输出:4 printf("%d\n", SECRET);//输出:5 return 0; }
【结论】枚举常量的定义类似于结构体的定义,和 enum 固定搭配使用。声明一个枚举常量后,不可再修改。
· 运算符是表示某种操作的符号,在C语言中,除控制语句和输入/输出函数外,其他所有基本操作都作为运算符处理。运算符的操作对象称为运算数,用运算符把运算数链连接起来的一个有意义的式子就叫做表达式
C语言运算符可以分为以下几类:
【注意】:如果操作数中有负数,则取整通常采用“向零取整”的方法。如5/-3 = -1
自增、自减运算符的两种用法:
int main() { int i = 2; printf("i=%d\n", i);//i=2 int j; j = ++i; printf("i=%d j=%d\n",i,j);//i=3 j=3 j = i--; printf("i=%d j=%d\n",i,j);//i=2 j=3 return 0; }
int main() { int x = 11; int sum = (x++ * 1 / 3); printf("%d,%d\n", x,sum);//12,3,所有运算都结束后再自增 return 0;
【注意】
C语言中赋值符号是“=”,它的作用是将赋值运算符右边表达式的值赋给左边的变量
int main() { int a = 5; int x = (a + 3) / 5; printf("a=%d, x=%d\n",a,x);//a=5, x=1 return 0; }
【注意】如果“=”两侧的类型不一致,则在赋值时要进行类型转换。
在赋值运算符“=”之前加上一个其他运算符,可以构成复合赋值运算符。C语言规定了如下10种复合赋值运算符(右结合性):+= -= *= /= %= &= |= ^= <<= >>=
C语言提供6种关系运算符:
>(大于) >=(大于等于) <(小于) <=(小于等于) ==(等于) !=(不等于)
在这6种关系运算符种,前4种关系运算符的优先级相同,后2种关系运算符的优先级相同,且前4种关系运算符的优先级高于后2种关系运算符的优先级。与其他运算符的优先级相比,关系运算符的优先级低于算术运算符,但高于赋值运算符
例如:
//c>a+b 等价于 c>(a+b) 算术运算符 //a==b>c 等价于 a==(b>c) 关系运算符 //a=b>c 等价于 a=(b>c) 赋值运算符
优先级:算术运算符>关系运算符>赋值运算符
int main() { int n1 = 3, n2 = 4, n3 = 5; printf("%d\n", n1 > n2);//0 printf("%d\n",(n1 > n2) != n3);//1 printf("%d\n", n1 < n2 < n3);//1 printf("%d\n", (n1 < n2) + n3);//6 return 0; }
关系表达式只能描述单一条件,如“x>=0”。如果需要描述“x>=0”同时“x<10”,就需要借助逻辑表达式
int main() { int a = 2, b; printf("%d\n", b=a==!a);//先算!a值为0,再算a==a值为0,最后算b=a值为0 return 0; }
int main() { int m = 1, n = 1, a = 1, b = 2, c = 3, d = 4; printf("%d\n", (m=a>b)&&(n=c>d));//0 printf("%d\n", m);//0 printf("%d\n", n);//1,对于逻辑与运算,如果第一个操作数被判定为“假”,则系统不再判定或求解第二个操作数 return 0; }
②对于逻辑或运算,如果第一个操作数被判定为“真”,则系统不再判定或求解第二个操作数
例如:
int main() { int m = 0, n = 0, a = 1, b = 2, c = 3, d = 4; printf("%d\n", (m = b > a) || (n = d > c));//1 printf("%d\n", m);//1 printf("%d\n", n);//0,对于逻辑或运算,如果第一个操作数被判定为“真”,则系统不再判定或求解第二个操作数 return 0; }
逗号运算符的优先级时C语言种所有运算符中最低的,结合方向为左结合
逗号表达式是由一系列逗号将表达式连接起来的式子,其一般形式如下:
表达式1, 表达式2, ···, 表达式n
逗号表达式的求解过程:由逗号隔开的一对表达式从自左至自右依次计算各表达式的值,“表达式n”的值即为整个逗号表达式的值
例如:
int main() { int a; printf("%d\n", (a = 2 + 3, a = a * 6, a / 10));//3, “表达式n”的值即为整个逗号表达式的值 return 0; }
C语言提供了以下6种位运算:
【补充】
int main() { int a = 0; printf("%d\n", ~a);//-2 return 0; }
sizeof() 是一个运算符,用于计算类型或变量的大小,也可计算数组大小
例:
int main() { long long a = 100; printf("%d\n", sizeof(int));//4 printf("%d\n", sizeof(a));//8 return 0; }
【注意】使用sizeof运算符时,计算函数大小时不能省略后面的 () ,只有当计算变量大小时可省略后面的 () 。规范写法通常都不省略
int main() { long long a = 100; printf("%d\n", sizeof (int));//4,计算函数大小时不可省略括号 printf("%d\n", sizeof a);//8,计算变量大小时可省略括号 return 0;
【补充】可利用 sizeof() 运算符计算数组元素个数,公式:sizeof(arr)/sizeof(arr[0])
int main() { int arr[10] = { 0 }; int sz = sizeof(arr) / sizeof(arr[0]); printf("%d\n", sz);//C语言中是用该方法计算数组元素个数的 return 0; }
公式:exp1 ? exp2 : exp3
规则:
int main() { int a = 0; int b = 3; int max = 0; max = a > b ? a : b; printf("%d\n", max);//3 return 0; }
[ ]:用于下标引用
例:
int main() { int arr[10] = { 0,1,2,3,4,5,6,7,8,9 }; printf("%d\n", arr[6]);//6,[]下标引用运算符 return 0; }
调用函数是,函数名后边的 () 就是函数调用运算符
例如:
int main() { //调用函数是,函数名后边的 () 就是函数调用运算符 printf("hehe\n"); printf("%d\n", 100); return 0; }
C语言允许在整形、实型、字符型等数据之间进行混合运算,在进行运算时,首先将不同类型的数据转换成同一类型,然后进行运算
例如:
数据类型转换关系:
①即使在同一种数据类型之间进行运算时,也要进行转换:
char——>short——>int
float——>double
②当运算对象类型不同时的转换
int——>unsigned——>long——>double
【注意】若int型和double型混合运算,不是int型先转为unsigned型,再转为long型,最后再转为double型,而是直接转为double型
可以利用强制类型转换运算符将一个表达式转换成所需类型。强制类型转换的一般格式如下:
(类型名)(表达式)
例如:
(double)a(等价于(double)(a)) //将变量a的值转换成double类型 (int)(x+y) //将x+y的结果转换成int型 (float)5/2(等价于(float)(5)/2) //将5转换成实型,再除以2(结果为2.5) (float)(5/2) //将5整除2的结果(2)转换成实型(2.0)
int main() { float a = (float)5 / 2; printf("%f\n", a);//2.5 float b = (float)(5/2); printf("%f\n", b);//2.0 return 0; }
【注意】在强制类型转换是,得到的是一个所需类型的中间量,原来变量的类型并不发生变化。如(double)a,只是将变量a的值转换成一个double型的中间量,a的数据类型并未转换成double型
int main() { int a = 10;//a在内存中要分配空间 - 4个字节 printf("%p\n", &a);//00AFF930 (%p - 专门用打印地址的) int* pa = &a;//pa是用来存放地址的,在C语言中pa叫指针变量 printf("%p\n", pa);//00AFF930 // * 说明:pa是指针变量 // int 说明:pa指向的对象是int类型的 char ch = 'w'; char* pc = &ch; printf("%p\n", pc);//012FF9EF return 0; }
【注意】%p - 专门用打印地址的
int main() { int a = 10; int* pa = &a; *pa = 20;//这里的 * 叫解引用操作, *pa 就是通过pa里边的地址,找到a printf("%d\n", a); return 0; }
int main() { printf("%d\n", sizeof(char *));//4 printf("%d\n", sizeof(short *));//4 printf("%d\n", sizeof(int *));//4 printf("%d\n", sizeof(long *));//4 printf("%d\n", sizeof(long long *));//4 printf("%d\n", sizeof(float *));//4 printf("%d\n", sizeof(double *));//4 return 0; }
(1). 运算符的用法:结构体的变量 . 成员变量
(2)-> 运算符的用法:结构体的指针 -> 成员变量
(3)*结构体指针变量 等价于 结构体的变量(*解引用操作)
//创建一个学生类型 struct Stu { char name[20];//成员变量 int age; double score; }; int main() { //结构体的创建和初始化 struct Stu s = { "张三", 20, 85.5 }; printf("1: %s %d %lf\n", s.name, s.age, s.score);// . 运算符 - (结构体变量 . 成员变量) struct Stu * ps = &s;//结构体指针变量 printf("2: %s %d %lf\n", (*ps).name, (*ps).age, (*ps).score);//等价于1的写法 //最直观的写法:结构体的指针->成员变量 printf("3: %s %d %lf\n", ps->name, ps->age, ps->score);//等价于2的写法 return 0; }
#include <stdio.h>
#define _CRT_SECURE_NO_WARNINGS 1
extern int g_val;
extern int Add(int x, int y);
typedef unsigned int u_int;//typedef 类型重定义 int main() { unsigned int num1 = 100; u_int num2 = 100; return 0; }
static - 静态的
(1)static修饰局部变量,改变了局部变量的生命周期(本质上是改变了变量的存储类型)
栈区 | 堆区 | 静态区 |
---|---|---|
局部变量 | 动态内存分配的 | 全局变量 |
函数的参数 | static修饰的静态变量 |
void test() { static int a = 1; a++; printf("%d ", a); } int main() { int i = 0; while (i < 10) { test();//2 3 4 5 6 7 8 9 10 11 i++; } return 0; }
(2)static修饰全局变量,使得全局变量只能在自己所在的源文件(.c文件)内部可以使用,其他源文件不能使用:
全局变量在其他源文件内部可以使用,是因为全局变量具有外部链接属性。但是被static修饰之后,就变成了内部链接属性,其他源文件就不能链接到这个静态的全局变量
(3)static修饰函数,使得函数只能在自己所在的源文件(.c)内部可以使用,其他源文件不能使用
【注意】本质上:static是将函数的外部链接属性变成了内部链接属性!(和static修饰全局变量一样)
#define定义常量和宏
(1)#define定义常量
//define 是一个预处理指令 //1.define定义符号 #define MAX 1000 int main() { printf("%d\n", MAX); return 0; }
(2)#define定义宏
格式:#define Add(x, y) ((x)+(y))
//2.define定义宏 #define Add(X,Y) ((X)+(Y))//需要给每个表达式加括号,保证其计算的优先级 int main() { printf("%d\n", 4*Add(2,3));//20 return 0; }
【注意】#define定义宏时,x和y可能是变量,也可能是表达式,所以需要加括号,保证其自己单独作为一个整体
【注意】