第二章 编程初步

春雨断桥人不渡,小舟撑出柳阴来。

变量的命名

变量的命名是很有弹性的。可以是一个或多个**大写字母/小写字母/数字/下划线(_)(有时候下划线也算作字母)**,但要以字母开头。下面是一些正确的变量名:

Radius diameter Auntie_May Knotted_Wool D678

下面是一些错误的变量名及其错误的原因:

8_Ball : 变量命不能以数字开头

Hash! : 变量名只能包含字母数字和下划线

Mary-Lou : 变量名只能包含字母数字和下划线

为了避免和标准库中的变量重名,尽量避免使用以下划线开头的变量名

在上述限制内,变量名尽量便于理解

变量名的长度取决于编译器,遵循C语言标准的编译器至少支31个字符,只要不超过这个长度就没有问题,有些编译器会截短过长的变量名。

基本运算符

运算符 动作
+
-
*
/
% 取模

需要两个操作数的运算符叫二元运算符

-data 中的“负号”叫一元运算符

注意:对于取模运算符,不管两个操作数符号是否相同,其结果总是和左边的操作数符号相同

45%-7 = 3; -45%-7 = -3.

变量与内存

带符号整数类型

类型名称 字节数
signed char 1
short int 2
int 4
long int 4
long long int 8

类型名称short/long/long long 可以用作short int/long int/long long int的缩写,前面还可以带有signed关键字。

无符号的整数类型

类型名称 字节数
unsigned char 1
unsigned short int 2
unsigned int 4
unsigned long int 4
unsigned long long int 8

如果位数给定,可以表示的数值就是固定的。

注意:如果变量的类型不同,但占用相同的字节数,则它们仍是不同的。Long 和 int 类型占用相同的内存量,但它们仍是不同的类型。

  • 早期的操作系统是16位系统,

    int用二字节表示,范围是-32768~32767;

    long用4字节表示,范围是-2147483648~2147483647。

  • 后来发展到32位操作系统,

    int 用4字节表示,与long相同。

  • 目前的操作系统已发展到64位操作系统,但因程序编译工艺的不同,两者表现出不同的差别:

    • 32位编译系统:int占四字节,与long相同。
    • 64位编译系统:int占四字节,long占8字节,long数据范围变为:-2^63~2^63-1

在整数后面加上L表示 long 类型的变量

在整数后面加上LL表示 long long 类型的整数

1
2
3
long a;
a = 123456; //或者 a = 123456L;
a = a + 456123L;

实际上感觉加不加L都问题不大,运算的时候会自动进行类型转换

浮点数

浮点数的表示方法如下:

浮点数的变量类型:

控制输出中的小数位数

%.3f : 只要小数点后三位

%.2f : 只要小数点后两位

%.0f : 只要整数部分

控制输出的字段的宽度

%[width] [.precision] [modifier]f

width 的值是一个整数,指定输出的总字符数(包括空格),当数据总长度大于width的时候按照总长度输出,不会出现输出不完整的情况。

precision 的值也是一个整数,指定小数点后面的位数

modifier 当输出的值的类型是 long double 的时候为 L, 否则就省略它。

%10.4f : 表示输出总长度为10,保留小数点后4位,默认为右对齐

%-10.4f : 右对齐

赋值的时候有f和没有f的区别

1
2
float a = 0.0f
float b = 1.23

a 和 b 都是浮点数,不带f同样可行,但是编译器需要进行不必要的转换。

变量类型和值域

变量的输入

scanf()函数

1
2
3
4
5
6
7
8
9
10
11
12
13
14
#include <stdio.h>
int main(){
int a;
int b;
printf("input a 输入a:\n");
scanf("%d", &a); //输入变量必须要用取址符
printf("input b 输入b:\n");
scanf("%d", &b);

printf("a 和 b 的和是:%d", a+b);

return 0;
}

读取数据的格式如下:

定义常量

第一种方法:

通过将PI定义为一个符号,在程序编译期间用派的值取代它,这个时候, PI不是一个变量,而是它表示的值的一个别名。

1
2
3
4
5
6

#define PI 3.14159f

#define HEIGHT 100

#define PI 3.14.159f //编译的时候报错

第二种方法:

将PI定义成变量,但告诉编译器,它的值是固定的,不能改变,声明变量时在变量名前加上const关键字,可以固化变量的值,例如:

1
const float Pi = 3.14159f;

编译器会检查代码是否试图改变它的值,如果是则会编译失败。

极限值

下表中定义的符号表示整数类型的极限值:

要在程序中使用这些符号,必须在源文件中添加#include <limits.h>

1
int number = INT_MAX;

下表中定义的符号表示浮点数类型的极限值:

**注意:使用浮点数极限值符号的时候要添加头文件 include <float.h> **

sizeof运算符

使用sizeof运算符可以确定给定的类型占据多少字节。

sizeof(int) 会得到int类型变量所占的字节数,得到的是 size_t 类型的整数

size_t 类型在标准头文件<stddef.h>中定义

size_t size = sizeof(long long);

1
2
3
4
5
printf("%d", sizeof(int));    //输出4 

float ff = 10.23f;
size_t st = sizeof(ff);
printf("%d", st); //输出4

强制类型转换

有时候数值计算要进行强制类型转换,否则计算结果就会不准确,例如:

1
2
3
4
5
6
7
8
9
10
double result = 0.0;
int a = 5;
int b = 8;

result = (double)(a + b)/2 - (a + b)/(double)(a*a + b*b);
printf("%f\n", result);

result = (a + b)/2 - (a + b)/(double)(a*a + b*b);

printf("%f", result);

像上面这样在变量面前加上(double)就是强制类型转换。

隐式类型转换

假如两个变量类型分别为intlong,这两个变量运算的时候编译器会自动将int类型转换成long类型(会将域值小的变量转换为域值大的变量)

隐式类型转换的规则如下:

  • 如果一个操作数是 long double 就把另外一个操作数转化为 long double 类型

  • 否则,如果一个操作数是 double 就把另一个操作数转换位 double 类型

  • 否则,如果一个操作数是 float 类型,就把另一个操作数转换为float类型

  • 否则,如果两个操作数的类型都是带符号的整数或无符号的整数,就把低的操作数转换为另一个操作数的类型。无符号整数类型的级别如下:

    signed char, short, int, long, long long

    每个无符号整数类型的级别都与对应的带符号整数类型相同,unsigned int 和 int 类型相同

  • 否则,如果带符号整数类型的操作数级别低于无符号整数类型的级别,就把带符号整数类型的操作数转换为无符号整数类型

  • 否则,如果带符号整数类型的值域包含了无符号整数类型所表示的值,就把无符号整数类型转换为带符号整数的类型

  • 否则两个操作数都转换为带符号整数类型对应的无符号整数类型

在赋值语句中也会进行隐式类型转换

1
2
3
int number = 0;
float value = 2.5f;
number = value; // number = 2

因此,隐式类型转换也会带来数据丢失的问题

字符类型

可以把一个字符看作是一个字符,也可以看作是一个整数

字符变量可以进行数值运算

1
2
3
4
5
6
char letter = 'A';
char digit = '9';
char exclamation = '!';
char newline = '\n';
char tab = '\t';
char single_quote = '\'';

输入一个字符:

1
2
char letter;
scanf("%c", &letter)

对字符进行输出:

1
2
printf("%c", letter);
printf("%c", single_quote);

枚举

在编程时常常希望变量存储一组可能值中的一个,例如,一个变量存储表示当前月份的值,,那么这个变量只有12种取值,C语言中的枚举就是用于这种情形

enum Weekday {Monday, Tuesday, Wednesday, Thursday, Friday, Saturday, Sunday};

可以通过下面语句初始化一个Weekday类型的新变量

enum Weekday today = Wednesday;

1
2
3
4
5
6
enum Weekday  {
Monday, Tuesday, Wednesday, Thursday, Firday, Saturday, Sunday
};
// 对应的值分别为0 1 2 3 4 5 6
enum Weekday today = Wednesday;
printf("\n%d", today); // 输出2

布尔值

_Bool类型存储布尔值

_Bool valid = 1; //将一个布尔变量初始化为true

bool 更简洁,但是使用 bool 的时候要添加头文件<stdbool.h>

否则会报错:unknown type name ‘bool’

数学函数

<math.h>头文件中包含很多数学函数,使用时别忘了加上头文件

下表列出了一些数值计算函数,它们都需要double类型的参数,返回值也是double类型

例子:

1
2
3
4
5
6
7
double x = 2.25;
double less = 0.0;
double more = 0.0;
double root = 0.0;
less = floor(x); //2.0
more = ceil(x); //3.0
root = sqrt(x); //1.5

例子:

1
2
3
4
5
6
double angle = 45.0;
double pi = 3.14159265;
double sine = 0.0;
double cosine = 0.0;
sine = sin(pi*angle/180.0); //0.707107
cosine = sin(pi*angle/180.0); //0.707107