( 接上篇——初识C语言(一) )
五、字符串与转义字符
1.字符串
“Hello World!\n”
这种由双引号" "引起来的一串字符称为字符串。
- 字符串的结束标志是一个 \0 的转义字符,隐藏在字符串的末尾。
- 在计算字符串长度的时候 \0 不算作字符串内容。
- printf() 可以通过 %s 打印字符串,从你给的地址开始打印,直到遇到 \0 停止。
例程1:
可以通过下面的例程,体会一下 \0 的作用
#include<stdio.h>
int main()
{
char ch0[] = {'a','b','c','d','e'}; //字符a、字符b、字符c、字符d、字符e
char ch1[] = { "abcde" }; //字符串abcde
printf("%s\n", ch0); //打印字符串
printf("%s\n", ch1);
return 0;
}
运行后的结果为:
打印字符串时没有出现乱码,因为字符串末尾有隐藏的 \0 ,%s 遇到 \0 就结束打印了。
但是打印单个字符时为什么会出现乱码呢?
例程2:
可以通过下面例程,看一看字符串的长度计算
#include<stdio.h>
#include <string.h>
int main()
{
int length1,length2 = 0;
char ch1[] = { 'a','b','c' }; //字符a、字符b、字符c
char ch2[] = { "abc" }; //字符串abc
length1 = strlen(ch1); //求字符串长度
length2 = strlen(ch2);
printf("%d\n", length1); //打印字符串长度
printf("%d\n", length2);
return 0;
}
运行结果为:
strlen() 是C库函数,是头文件 string.h 中定义的函数,作用是求字符串长度。strlen() 函数会从你给的地址开始向后数字符,直到遇到 \0 结束(字符串长度不包括 \0)。
运行结果中,计算出的第一个长度为什么是 12 呢?
其实原因与例程1是一样的,字符是没有 \0 作为结尾的,后续的内存放了什么东西我们不得而知,因此 strlen() 会一直往后数,直到遇到\0 。这里的 12 是随机值,也可能是其他数值。
2.转义字符
转义,也就是转换字符的意义。
字符 | 说明 |
\? | 在书写连续多个问号时使用,防止他们被解析成三字母词( ??)在有些编译器中会被认为是 ] ) |
\' | 用于表示字符常量 |
\“ | 用于表示一个字符串内部的双引号 |
\\ | 用于表示一个反斜杠,防止它被解释为一个转义序列符 |
\a | 警告字符,蜂鸣 |
\b | 退格符 |
\f | 进纸符 |
\n | 换行 |
\r | 回车 |
\t | 水平制表符 |
\v | 垂直制表符 |
\ddd | ddd表示1~3个八进制的数字。 如: \130 X |
\xdd | dd表示2个十六进制数字。 如: \x30 0 |
在这里,我们主要看一下 \ddd 和 \xdd 这两个转义字符。
例程1:转义字符 \ddd
#include<stdio.h>
int main()
{
printf("%c", '\133');
return 0;
}
%c 可以帮助我们打印单个字符。运行结果为:
这个 [ 与ASCII码有关,可见用转义字符 /ddd 可以输出八进制对应的ASCII码。对于ASCII码,我们现阶段只要会对照ASCII码表就可以了,ASCII码表百度就可以搜到。
\133 是八进制数,换算为十进制是91。对照ASCII码表能看到,十进制数91对应的图形就是 [ 。
八进制 | 十六进制 | 十进制 | 图形 |
133 | 5B | 91 | [ |
例程2:转义字符 \xdd
#include<stdio.h>
int main()
{
printf("%c", '\x31');
return 0;
}
运行结果为:
转义字符 \x31 表述的是十六进制31,换算成十进制为49。对照ASCII码表能看到,十进制数49对应的图形就是数字1 。
八进制 | 十六进制 | 十进制 | 图形 |
61 | 31 | 49 | 1 |
可见,转义字符 /xdd 可以输出十六进制对应的ASCII码。
例程3: 小测试
这里有个小测试,数一下字符串 c:\test\x11\328\test.c 有多长
#include <stdio.h>
#include<string.h>
int main()
{
printf("%d\n", strlen("c:\test\x11\328\test.c"));
return 0;
}
运行结果如下:
现在我们来一起数一下:'c' ':' '\t' 'e' 's' 't' '\x11' '\32' '8' '\t' 'e' 's' 't' '.' 'c' , 总共15个。其中要注意“\328”,八进制数是0~7,因此 \32 是八进制数,8是一个单独的字符。
六、选择语句
在初识C语言阶段,我们不需要深入了解选择语句,这里只需要有个概念,能写简单的逻辑就好。
选择语句有 if 语句和 switch 语句,这里只简单说一下 if 语句。
if 语句的基本框架为:
if(条件)
{
要执行的语句; //如果条件为真就执行这里的语句
}
else
{
要执行的语句 //如果条件为假就执行这里的语句
}
一个 if 对应0个或1个else。if 后面也可以对应 else if...else...,以测试更多的条件。
- C语言中,0为假,非0都为真。
- 满足条件即为真,不满足条件即为假。如 if(flag==1),如果满足 flag==1我们就能说条件为真,不满足就是假。
上一段代码,一开始看不懂也没关系,后面会专门详细讲解 if 和 switch 语句。
#include<stdio.h>
int main()
{
printf("如果你好好学习了就输入1,否则输入0\n");
int flag = 0; //初始化变量flag
scanf("%d", &flag); //你输入的值,保存在变量flag中
if(flag == 1) //如果输入1
printf("你真棒\n");
else if(flag==0) //如果输入0
printf("大鼻窦\n");
return 0;
}
代码执行结果为:
七、循环语句
生活中有许多事情会日复一日发生,因此要用到循环语句。同样的,循环语句我们也只要有个概念就好,后面会详细讲解。循环语句有 while 、for 和 do while ,这里只简单说一下while语句。
while循环语句的基本框架为:
while(条件)
{
循环语句; //条件为真时会一直执行循环语句,直到条件为假会跳出循环
}
条件为真时,进入循环语句;条件为假时,跳出循环语句。跳出循环后会执行紧接着的下一语句。
举一个例子:如果没学够7天就一直学习
#include<stdio.h>
int main()
{
int day = 0; //学习天数存在变量day中
while (day < 8) //没学够7天就一直循环
{
printf("学习天数:%d\n", day);
day++; //天数+1
}
if (day == 8)
printf("你太棒了\n");
return 0;
}
代码执行结果为:
八、函数
我们在数学中学过函数,那时函数的定义与集合、映射有关。与数学定义完全不同,我们现在所说的函数可以理解为一个模块的代码,完成一个独立的功能。
通过例程来理解一下:
#include<stdio.h>
int Add(int x, int y) //自定义的函数,用于求两数之和
{
int z = x + y;
return z; //返回值
}
int main()
{
int a, b, sum = 0; //初始化参数
scanf("%d %d", &a, &b); //输入
sum = Add(a, b); //调用函数求和
printf("%d\n", sum); //输出和
return 0;
}
运行结果为:
上面的例程中,我们写了一个函数 Add(),用于求两整数之和。
函数的特点就是简化代码,代码复用。
这里先重提一下C库函数:
- C库函数:C语言内部提供的函数,我们引用对应的头文件后可以直接调用,如 printf()。
- 自定义函数:我们自己定义编写的函数。
通过例程中的 Add() 函数,可以拆分出函数的组成,这里与上一篇的 main() 函数对应:
- 函数名:例程中,函数名是 Add。
- 函数返回值:在例程中,函数名之前的 int 表示该函数返回值为整型,返回值是两个数的和。有些函数不返回值,那函数名之前是 void。
- 参数:x 和 y 是函数定义的两个参数,叫做形式形参。当函数被调用时,我们传递的 a、b 两个值,叫做实际参数。
- 函数主体:大括号中的内容就是函数主体。
九、数组
数组用于存储一组相同类型的数据。
9.1 数组的定义
int arr[10] = {1,2,3,4,5,6,7,8,9,10}; | 定义了一个整型数组,包含10个元素 |
int 表示数组中数据的类型;arr 为数组名;大括号{ }中为组成数组的数据 |
- 数组初始化时,可以不直接指定大小,数组的大小会根据初始化的内容来确定。
- 如:int arr[ ] = { 1 , 2 , 3 }; 虽然未指定数组大小,但是由大括号中的内容可以看出来,数组中包含3个元素。
- 又如:int arr[10] = { 1 , 2 , 3 }; 数组中含有10个元素,前三个元素分别是1、2、3,后七个元素则均为0 。
- 再如:int n = 10; int arr[n] = {0}; 应当注意这种数组初始化方法是错误的!C99标准之前数组的大小不能是变量,C99标准引入了变长数组的概念,此时允许数组大小是变量,但是这种数组不能直接初始化。我用的编程软件VS不支持变长数组,gcc编译器支持变长数组。
9.2 数组的下标
数组的每个元素都有一个下标,下标从0开始,数组可以通过下标访问。
如: int arr[10] = {0}; 该数组有10个元素,下标为0~9
int arr[10] | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 |
下标 | 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 |
9.3 数组的使用
如下例程,利用下标循环输出数组:
#include<stdio.h>
int main()
{
int arr[10] = { 1,2,3,4,5,6,7,8,9,10 }; //定义数组
int i = 0; //初始化下标
while (i < 10)
{
printf("%d", arr[i]); //下标为0~9,输出数组中的所有数据
i++;
}
return 0;
}
运行结果为:
十、操作符
C语言有很多操作符,甚至可以操作到二进制位,因此使用起来很灵活。
算术操作符:
+ - * / % ( 加 减 乘 除 取模 )
/ ----> 除:计算结果是整除之后得到的商。
- 包括整数除法与浮点数除法。
- 整数除法:如 7/2,结果为3(整数除法结果不包括小数部分)。
- 浮点数除法:应当保证除数和被除数中至少有一个数是浮点数。如:7/2.0 或者 7.0/2 或者7.0/2.0
关于整数和浮点数除法的结果,我们可以通过代码看一看:
#include<stdio.h>
int main()
{
printf("%d\n", 7 / 2);
printf("%lf\n", 7.0 / 2); // %lf 打印double类型的浮点数
printf("%lf\n", 7 / 2.0);
printf("%lf\n", 7.0 / 2.0);
return 0;
}
运行结果:
% ----> 取模(取余):得到的是余数,只适用于整数,不能用于小数。
移位操作符
>> <<
移动的是二进制位,这里不做介绍,后面会详细讲解。
位操作符
& ^ |
移动的是二进制位,这里不做介绍,后面会详细讲解。
赋值操作符
= | a = 10; 赋值符,将右边的值赋给左边变量,应当与 == (等于) 做区分。 |
+= | a = a + 5; 可以写成 a += 5; |
-= | a = a - 5; 可以写成 a -= 5; |
*= | a = a * 5; 可以写成 a *= 5; |
/= | a = a / 5; 可以写成 a /= 5; |
&= ^= |= >>= <<= 这组操作符是按位运算,这里不做介绍,后面会详细讲。
单目操作符
双目操作符:有两个操作数。如:2+3,2和3是两个操作数,所以加号 + 是双目操作符。
单目操作符:只有一个操作数。
- c语言中如何表示真假呢?
- 0为假 ;非0为真
! | 逻辑反操作 若 a 为真,则 !a 为假 |
- | 负值 -1也为真 |
+ | 正值 |
& | 取地址 |
sizeof | 操作数的类型长度(单位:字节) |
~ | 对一个数的二级制按位取反 |
-- | 前置、后置-- |
++ | 前置、后置++ |
* | 间接访问操作符(解引用操作符) |
(类型) | 强制类型转换 |
- sizeof 前面提到过,可以计算变量占有内存的大小,这里再强调一下,sizeof 是操作符,不是函数。关于这一点,可以看一看下面的例程:
#include<stdio.h>
int main()
{
int a = 100;
printf("%d\n", sizeof(a)); //sizeof(a)和sizeof(int)是一样的,变量a的数据类型是int
printf("%d\n", sizeof a); //变量的括号可以省略,说明sizeof不是函数,函数的括号不能省略
printf("%d\n", sizeof(int)); //数据类型的括号不可以省略
return 0;
}
代码运行结果为:
- 前置++:先++,后使用
- 后置++:先使用,后++
- 前置-- / 后置-- 的运算规则与++ 相同
- 举个例子:
a = 1,b = ++a,那么 a 与 b 分别为多少? |
前置++,应当先计算,后使用。应当先计算 a=a+1=2,再将 2 赋给 b,因此 a、b 均为2。 |
#include<stdio.h>
int main()
{
int a = 1;
int b = ++a;
printf("a=%d b=%d\n", a, b); //输出a,b
return 0;
}
运行结果为:
a = 1,b = a++,那么 a 与 b 分别为多少? |
后置++,应当先使用,后计算。应当先将 a 赋给 b,故 b 为 1;再计算 a=a+1=2,因此 a 为 2。 |
#include<stdio.h>
int main()
{
int a = 1;
int b = a++;
printf("a=%d b=%d\n", a, b);
return 0;
}
运行结果为:
关系操作符
> | 大于 |
>= | 大于等于 |
< | 小于 |
<= | 小于等于 |
!= | 用于测试“不相等” |
== | 用于测试“相等” |
逻辑操作符
&& 逻辑与 “并且” | 两个操作数都为真才为真,只要有一个为假就为假 |
|| 逻辑或 “或者” | 两个操作数只要有一个为真则为真,两个同时为假才为假 |
条件操作符(也叫三目运算符)
书写形式: exp1 ? exp2 : exp3 (exp1、exp2和exp3为三个表达式)
释义: 若exp1为真,则执行exp2;若exp1为假,则执行exp3,执行表达式的结果为最终结果。
下面的例程中,三目运算符用来判断两个数的大小:
#include<stdio.h>
int main()
{
int a = 0;
int b = 0;
int m = 0; //变量初始化
scanf("%d %d", &a, &b); //输入a、b
m = (a > b ? a : b); //用三目运算符判断大小
printf("m=%d\n", m); //输出较大的数
return 0;
}
运行结果为:
逗号操作符
exp1, exp2, exp3, …expN
逗号表达式应当从左到右依次计算(注意:不能只计算最后一个表达式),逗号表达式的结果是最后一个表达式的结果。
逗号表达式的结果可以通过下面的例程理解:
#include<stdio.h>
int main()
{
int a = 1;
int b = 2;
int c = 3; //变量初始化
int d = (a+=3,b-=1,c=a+b,c-3); //逗号表达式
// a=a+3=4,b=b-1=1,c=4+1=5,c-3=2
printf("%d\n", d); //输出d
return 0;
}
运行结果为:
下标引用、函数调用和结构成员
[ ] 下标引用,数组中常用
( ) 函数调用
. -> 结构成员,放在指针中说明
(未完待续)