C 语言学习笔记(二)字符串和格式化输入/输出

1. 字符串

1.1 字符串简介

  字符串(character string)是一个或多个字符的序列。例如:“a”、“abc”、“123”、“Hello World!”。其中双引号不是字符串的一部分,双引号只是告诉编译器它括起来的是字符串。
  C 语言中没有专门用来存储字符串的的变量类型,字符串都被存储在 char 类型的数组中。数组由连续的存储单元组成,字符串中的字符被存储在相邻的存储单元中,每个单元存储一个字符。

在这里插入图片描述
  其中每一个存储单元一个字节,数组末尾位置的字符是 /0。这是空字符,C 语言用它标记字符串的结束。C 中字符串一定以空字符结尾,所以数组的容量至少比待存储的字符串中字符数多 1。
  那么什么是数组?数组可以看做一行连续的多个存储单元,更正式的说法是,数组是同类型数据元素的有序序列。

1.2 strlen() 函数

  上一篇博客提到了 sizeof 运算符,它以字节为单位给出对象的大小。而 strlen() 函数给出字符串中字符的长度。

#include <stdio.h>
#include <string.h>

#define S "Hello world!"

int main(void)
{
        char name[40];
        printf("What's your name?\n");
        scanf("%s",name);
        printf("Hello %s\n",name);
        printf("Your name of %zd letters occupies %zd memory cells.\n",strlen(name),sizeof name);
        printf("The phrase of S has %zd letters and occupies %zd momory cells.\n",strlen(S),sizeof S);
        return 0;
}

在这里插入图片描述
  上面程序中,name 数组有 40 个存储单元,但是只有 3 个单元用来存储 Tom,所以 strlen() 得出的结果是 3。name 数组的第 4 个单元存储空字符 \0,但是 strlen() 并不将它计入其中。对于字符串 S,用 strlen() 得出是字符串中字符的个数,而 sizeof 运算符给出的数比前者大 1,因为它要将字符串最后的空字符计算其中。
  上面程序中,sizeof 圆括号的使用取决于运算对象是类型还是特定量。运算对象是类型时,圆括号必不可少,但是对于特定量,可有可无。尽管如此,还是推荐所有情况下都使用圆括号。

2. 常量

2.1 明示常量(符号常量)

  预处理器也可以用来定义常量,只需要在程序顶部添加一行语句,语句语法格式为:

#define NAME value

  实际应用时,用选定的符号常量名和合适的值替换 NAME 和 value。用大写表示常量符号是 C 语言一贯的传统。例如:#define NUM 1.5 ,编译程序时,程序中所有的 NUM 都会被替换成 1.5。这一过程被称为编译时替换。通常,这样定义的常量也称为 明示常量。#define 指令还可以定义字符和字符串常量。前者使用单引号,后者使用双引号。
  C 头文件 limits.h 和float.h 分别提供了与整数类型和浮点类型大小限制相关的详细信息。每个头文件都定义了一系列供实现使用的明示常量。

limits.h 中一些明示常量
明示常量 含义 明示常量 含义 明示常量 含义
CHAR_BIT char 类型的位数 CHAR_MAX char 类型最大值 CHAR_MIN char 类型最小值
SCHAR_MAX signed char 类型最大值 SCHAR_MIN signed char 类型最小值 UCHAR_MAX unsigned char 类型最大值
SHRT_MAX short 类型最大值 SHRT_MIN short 类型最小值 USHR_MAX unsigned short 类型最大值
INT_MAX int 类型最大值 INT_MIN int 类型最小值 UINT_MAX unsigned int 类型最大值
LONG_MAX long 类型最大值 LONG_MIN long 类型最小值 ULONG_MAX unsigned long 类型最大值
LLONG_MAX long long 类型最大值 LLONG_MIN long long 类型最小值 ULLONG_MAX unsigned long long 类型最大值

float.h 中一些明示常量
明示常量 含义 明示常量 含义
FLT_MANT_DIG float 类型的位数位数 FLT_DIG float 类型的最少有效数字位数
FLT_MIN_10_EXP 带全部有效数字的 float 类型的最小负指数 FLT_MAX_10_EXP float 类型的最大正指数
FLT_MIN 保留全部精度的 float 类型最小正数 FLT_MAX float 类型最大正数

  其中把明示常量名中的 FLT 分别替换成 DBL 和 LDBL,即可分别表示 double 和 long double 类型对应的明示常量。

2.2 const 限定符

  C90 标准增加了const 关键字,用于限定一个变量为只读。注意,在 C 语言中,用 const 类型限定符声明的是变量,不是常量。
  例如:下面的 NUM 成为一个只读值,即不可更改 NUM 的值。

const int NUM = 12;

3. printf 函数

  printf() 和 scanf() 函数是输入/输出函数,简称 I/O 函数

3.1 printf 函数用法

printf(格式字符串,待打印项1,待打印项2,……)

  举个例子:

printf("His name is %s,and his age is %d.\n",name,age)

  待打印项可以是变量、常量、甚至是在打印之前先要计算的表达式。格式字符串应包含每个待打印项对应的转换说明。上面的例子中,格式化字符串是双引号括起来的内容,其中的 %s 和 %d ,这些符号被称为 转换说明,它们指定了如何把数据转换成可显示的形式。如果只打印短语或句子,就不需要使用任何转换说明。

3.2 printf 转换说明

转换说明及输出结果
转换说明 输出 转换说明 输出
%a 和 %A 浮点数、十六进制数和 p 计数法(C99/C11) %c 单个字符
%d 有符号十进制整数 %e 或 %E 浮点数、e 计数法
%f 浮点数、十进制计数法 %g 或 %G 根据值不同,自动选择 %f 或 %e。
%i 有符号十进制整数(与 %d 相同) %o 无符号八进制整数
%p 指针 %s 字符串
%u 无符号十进制整数 %x 或 %X 无符号十六进制整数
%% 一个百分号

3.3 printf 修饰符

  在 % 和 转换字符之间插入修饰符可以修饰基本的转换说明。

printf() 的修饰符
修饰符 说明
标记 一共有 5 种标记(-、+、空格、#、0),下面表格具体说明。可以不使用或使用多个标记。例:“%-10d”
数字 表示最小字段宽度。如果该字段不能容纳待打印数字或字符串,系统会使用更宽的字段。例: “%4d”
. 数字 表示精度。
对于 %e,%E 和 %f,表示小数点右边数字的位数
对于 &g 和 %G,表示有效数字的最大位数
对于%s,表示待打印字符的最大数量
对于 %d,表示待打印数字的最小位数,若有必要,使用前导 0 来达到这个位数
只使用 . 表示其后跟随一个 0,所以 . f 和 . 0f 相同
例:“%5.2f”
h 和整型转换说明一起使用,表示 short int 或 unsigned short int 类型的值。例:“%hu”、“%hx”
hh 和整型转换说明一起使用,表示 short char 或 unsigned char 类型的值。 例:“%hhu”、“%hhx”
j 和整数类型说明一起使用,表示 intmax_t 或 uintmax_t。这些类型定义在 stdint.h 中。例:“%jd”、“%8jx”
l 和整型转换说明一起使用,表示 long int 或 unsigned long int 类型的值。例:“%ld”、“%8lu”
ll 和整型转换说明一起使用,表示 long long int 或 unsigned long long int 类型的值。(C99) 例:“%lld”、“%8llu”
L 和浮点型转换说明一起使用,表示 long double 类型的值。例:“%Ld”、“%10.4Le”
t 和整型转换说明一起使用,表示 ptrdiff_t 类型的值。ptrdiff_t 是两个指针差值的类型。(C99) 例:“%td”
z 和整型转换说明一起使用,表示 size_t 类型的值。size_t 是 sizeof 返回的类型。(C99)例:“%zd”
printf() 中的标记
标记 含义
- 表示待打印项左对齐。例:“%-20s”
+ 有符号值为正,则在前面显示加号;若为负,则在前面显示减号。 例:“%+6.2f”
空格 有符号值为正,则在前面显示前导空格(不显示任何符号);若为负,则在前面显示减号。
+ 标记覆盖一个空格。例:“%6.2f”
# 把结果转换为另一种形式。
如果是 %o 格式,则以 0 开始;若以 %x 或 %X 格式,则以 0x 或 0X 开始;
对于所有浮点格式,# 保证了即使后面没有任何数字,也打印一个小数点字符;
对于 %g 和 %G,# 防止结果后面的 0 被剔除。
例:“%#o”、“%#8.0f”
0 对于数值格式,用前导 0 代替空格填充字段宽度。对于整数格式,如果出现 - 标记或指定精度,则忽略该标记。

printf() 函数练习:

#include <stdio.h> 
#define NUM 123 
#define PRASE "Hello World!"

int main(void) 
{
	// 字段宽度在打印整数时的效果
	printf("*%d*\n", NUM); 
	printf("*%2d*\n", NUM);
	printf("*%10d*\n", NUM);
	printf("*%-10d*\n", NUM);
	printf("-------------------------\n");

	// 浮点型格式
	const double MONEY = 9817.58; 
	printf("*%f*\n", MONEY); 
	printf("*%e*\n", MONEY); 
	printf("*%4.2f*\n", MONEY); 
	printf("*%3.1f*\n", MONEY); 
	printf("*%10.3f*\n", MONEY); 
	printf("*%10.3E*\n", MONEY); 
	printf("*%+4.2f*\n", MONEY);
	printf("*%010.2f*\n", MONEY);
	printf("-------------------------\n");

	// 格式标记
	printf("%x %X %#x\n", 25, 25, 25); 
	printf("**%d**% d**% d**\n", 58, 58, -58); 
	printf("**%5d**%5.3d**%05d**%05.3d**\n", 6, 6, 6, 6);
	printf("-------------------------\n");

	// 字符串格式
	printf("[%2s]\n", PRASE); 
	printf("[%24s]\n", PRASE); 
	printf("[%24.5s]\n", PRASE); 
	printf("[%-24.5s]\n", PRASE);

	return 0;
}

在这里插入图片描述

3.4 printf 返回值

  printf() 函数也有一个返回值,它返回打印字符的个数,这里计算的是所有字符,包括空格和不可见换行符等。如果输出有误,则返回一个负值(printf() 的旧版会返回不同的值)。

3.5 输出较长字符串的三种方式

  1. 使用多个 printf() 函数。
  2. 用反斜杠(\)和 Enter 键组合来断行。注意的是下一行代码必须从最左面开始。
  3. ANSI C 引入的字符串连接。在两个用双引号括起来的字符串之间用空白隔开,C 编译器会把多个字符串看做是一个字符串。
#include <stdio.h> 

int main(void) 
{ 
	printf("Here's one way to print a "); 
	printf("long string.\n"); 
	printf("Here's another way to print a \
long string.\n"); 
	printf("Here's the newest way to print a " "long string.\n"); 

	return 0; 
}

在这里插入图片描述

4. scanf() 函数

4.1 scanf 函数用法

  C 库中包含多个输入函数,scanf() 是最通用的一个,scanf() 和 printf() 类似,也使用格式字符串和参数列表。两个函数的主要区别在于参数列表中。printf() 函数使用变量、常量和表达式,而 scanf() 函数使用 指向变量的指针。指针会在后面详细介绍,这里只做了解,只需记住两条规则:

  1. 如果用 scanf() 读取基本变量类型的值,在变量名前加上一个 &;
  2. 如果用 scanf() 把字符串读入字符串数组中,不要使用 &。
#include <stdio.h>

int main(void) 
{
	int age;         
	float assets;
	char pet[30]; 

	printf("Enter your age, assets, and favorite pet.\n"); 
	scanf("%d %f", &age, &assets); 
	scanf("%s", pet); 
	printf("%d $%.2f %s\n", age, assets, pet);
	return 0; 
}

在这里插入图片描述
  scanf() 函数使用空白(换行符、制表符和空格)把输入分为多个字段。在依次把转换说明和字段匹配时跳过空白。唯一的例外是 %c 转换说明,根据 %c,scanf() 会读取每个字符,包括空白。

4.2 scanf 转换说明

scanf() 的转换说明
转换说明 含义 转换说明 含义
%c 把输入解释成字符 %d 把输入解释成有符号十进制整数
%e,%f,%g,%a
%E,%F,%G,%A
把输入解释成浮点数 %i 把输入解释成有符号十进制整数
%o 把输入解释成有符号八进制整数 %p 把输入解释成指针(地址)
%s 把输入解释成字符串。从第 1 个非空白字符开始,
到下一个空白字符之前的所有字符都是输入
%u 把输入解释成无符号十进制整数
%x 或 %X 把输入解释成有符号十六进制整数

4.3 scanf 修饰符

  在 % 和 转换字符之间插入修饰符可以修饰基本的转换说明。

scanf() 的修饰符
修饰符 说明
* 抑制赋值。例:“%*d”
数字 表示最大字段宽度。输入达到最大字段宽度处,或第 1 次遇到空白符时停止。例: “%10s”
hh 把整数作为 signed char 或 unsigned char l类型读取。例:“%hhd”、“%hhu”
ll 把整数作为 long long 或 unsigned long long 类型读取。(C99) 例:“%lld”、“%llu”
h、l 或 L “%hd” 和 “%hi” 表明把对应的值存储为 short int 类型
"%ho"、“%hx” 和 “hu” 表明把对应的值存储为 unsigned short int 类型
"%ld" 和 “li” 表明把对应的数值存储为 long 类型
“%lo”、“%lx” 和 “%lu” 表明把对应的值存储为 unsigned long 类型
"%le"、“%lf” 和 “%lg” 表明把对应值存储为 double 类型
在 e、f 和 g 前面使用 L 而不是 l 时,表明把对应的值存储为 long double 类型
如果没有修饰符,d、i、o 和 x 表明把对应的值存储为 int 类型,f 和 g 表明把对应的值存储为 float 类型
j 和整型转换说明一起使用,表明使用 intmax_t 或 uintmax_t 类型。例:“%jd”、“%jx”
t 和整型转换说明一起使用,表明使用两个指针差值的类型。(C99) 例:“%td”
z 和整型转换说明一起使用,表明使用 sizeof 的返回类型。(C99)例:“%zd”

4.4 scanf 返回值

  scanf() 函数返回成功读取的项数。如果没有读取任何项,且需要读取一个数字而用户输入一个非数值字符串,scanf() 便返回 0。当 scanf() 检测到 “文件末尾” 时,会返回 EOF(EOF 是 stdio.h 中定义的特殊值,通常用 #define 指令把 EOF 定义为 -1)。

发布了14 篇原创文章 · 获赞 33 · 访问量 1523

猜你喜欢

转载自blog.csdn.net/weixin_42837961/article/details/104426145
今日推荐