C-lang:格式化输入输出


这是2019年5月15日写的C语言笔记,从简书迁移过来。

Ax前导程序


//开始学第四章了,字符串的输出和输入。这是第一个简单程序
#include<stdio.h>
#include<string.h>      //提供trlen()函数的原型

#define DENSITY 62.4    //人体密度 density
int main()
{
    float weight, volume;
    int size, letters;
    char name[40];          //name是一个可容纳40个字符的数组,但是只能储存39个,最后一个是空NULL或者\0
//[40]表明该数组有40个元素数量
    printf("Hi! What's your first name?\n",name);
    /*%s转换说明来处理字符串的输入和输出,没有&*/
    scanf("%s",name);
    printf("%s,what's your weight in pounds?\n",name);
    scanf("%f",&weight);
    size = sizeof name;
    volume = weight / DENSITY;
    printf("Well, %s, your volume is %2.2f cubic feet.\n",name,volume);
    printf("Also,your first name has %d letters,\n",letters);
    printf("and we have %d bytes to store it. \n",size);

    return 0;

}

运行结果如下:

Hi! What's your first name?
enomothem
enomothem,what's your weight in pounds?
120
Well, enomothem, your volume is 1.92 cubic feet.
Also,your first name has 52 letters,
and we have 60 bytes to store it.

新特性

  • 数组(array)储存字符串(character string),该程序的数组占用内存的40个字节。
  • %s字符转换用来处理字符串的输入和输出。name没有&
  • #define预处理器定义DENSITY字符常量为62.4
  • 用C函数strlen()获取字符串长度

Bx字符串简介


字符串(character string)是一个或多个字符的序列。
例如:“kfwejfoiawhjfil;awjfjwaeofjioaewfj” // 随便打的 *-*
字符串必须创建数组,最后一位为NULL,计算机会处理好,注意不要溢出就行。

char类型数组和NULL字符

//使用不同类型的字符串
#include<stdio.h>
#define PRAISE "You are an extraordinary being."
#define LJ "这个好,轻松。"

//不用在字符串末尾加Null空字符串,编译器会自动加哟!
//你就是一个非凡的存在!
int main(void)
{
    char name[40];

    printf("What's your name?\n");
    scanf("%s",name);   //scanf()中的字符串只能识别一个字符串,如有空格,就不会识别空格后面的。
    printf("Hello,%s. %s\n",name, PRAISE); //%s告诉rintf()打印一个字符串。

    printf("%s,%s",name, LJ);

    return 0;
}

运行结果如下:

What's your name?
xing he
Hello,? You are an extraordinary being.
xing,这个好,轻松。

字符串和字符

区别于字符是’’,是基本类型(char),字符串是” “是派生类型(char 数组),字符串后面加上NULL 。

strlen()函数

strlen()函数给出字符串中的字符长度

/* trlen */
#include<stdio.h>
#include<string.h>
#define PRAISE "You are an extraodinary being."

int main(void)
{
    char name[42];

    printf("What's your name?");
    scanf("%s",name);
    printf("Hello, %s. %s\n",name,PRAISE);
    printf("Your name of %zd letters occupies %zd memory cells.\n"
           ,strlen(name),sizeof name);
    //sizeof 和 strlen 都是重要的编程工具。
    printf("The phrase of praise has %zd letters",strlen(PRAISE));//不计算NULL
    printf("and occupies %zd memory cells.\n",sizeof(PRAISE)); //计算NULL,括号可有可无,好习惯是加上

    return 0;

}

运行结果如下:

What's your name?yun ge
Hello, yun. You are an extraodinary being.
Your name of 3 letters occupies 42 memory cells.
The phrase of praise has 30 lettersand occupies 31 memory cells.

程序中加入头文件
#include<string.h>
当中,sizeof运算符使用%zd转换说明,对于strlen()同样适用。
还有就是括号,sizeof(char);这是对于类型,对于特定量,则不用。
下面我来学习define指定

常量和C预处理器

关键词:符号常量/常量(或明示常量)/编译时替换/常量的命名

在计算是,有一些是固定不变的,我们称为常量,那么我们在C里面也会给一个变量定义为某个固定的数字,不过会随着程序的变化而改变,所以我们需要一个常量来保证常量的不变,所以就有了一个Define指令。

常量称为 符号常量(symbolic constant),使用它会更方便
1.常量名比数字表达更多信息。

–创建符号常量?
float xxx;
xxx = 0.013;

但xxx是一个变量,程序可能会改变它的值,所以C提供了更好的方案–C预处理器
预处理器也可以来定义常量
#define TAXRATE 0.015
编译程序时,TAXRATE都会编译成0.015.这一过程称为编译时替换(compile-timesub stitution)
也称为 明示常量(manifest constant)= 符号常量

定义的格式:

define NAME value //用大写定义C语言常量是一贯的传统,提高可读性

//在比萨饼程序中使用定义的常量
#include<stdio.h>
#define PI 3.14159  // 圆周率
int main(void)
{
    float area, circum, radius;

    printf("What is the radius of your pizza?\n");
    scanf("%f",&radius);
    a  rea = PI *radius * radius;
    circum = 2.0 * PI * radius;
    printf("Your basic pizza parameters are as  follows: \n");
    printf("circumference = %1.2f,area = %1.2f\n",circum,area);

    return 0;
}

运行结果如下:

What is the radius of your pizza?
12
Your basic pizza parameters are as  follows:
circumference = 75.40,area = 452.39

注意格式,和命名,还有必要加上注释,这些都是良好的习惯。
###const限定符
const限定了变量不可更改,只可读。

明示常量

// efines.c -- 使用limit.h和float头文件中定义的明示常量
#include<stdio.h>
#include<limits.h>
#include<float.h>
int main(void)
{
    printf("Some number limits for this system:\n");
    printf("Biggest int: %d\n", INT_MAX );
    printf("Smallest long long:%lld\n", LLONG_MIN);
    printf("One byte = %d bits on this system\n",CHAR_BIT);
    printf("Largest double: %e\n",DBL_MAX);
    printf("Smallest normal float: %e\n",FLT_MIN);
    printf("float precision =%d digits\n", FLT_DIG);
    printf("float epsilon = %e\n",FLT_EPSILON);

    return 0;
}

输出如下:

Some number limits for this system:
Biggest int: 2147483647
Smallest long long:-9223372036854775808
One byte = 8 bits on this system
Largest double: 1.797693e+308
Smallest normal float: 1.175494e-038
float precision =6 digits
float epsilon = 1.192093e-007

Dx_printf()和scanf()

printf()是输出函数,scanf()是输入函数,可以让用户交互,简称为I/O.
不同版本的I/O不同。

printf()函数

请求printf()函数打印数据的指令要于待打印的类型相匹配,这个在前面的第三章里讲到过,打印整数时使用%d,打印字符时使用%c,此类符号称之为转换说明(conversion specification)

转换说明 输出
%a 浮点数、十六进制和p计数法
%A 浮点数、十六进制和p计数法
%c 单个字符
%d 有符号的十进制数
%e 浮点数,e计数法
%E 浮点数,e计数法
%f 浮点数,十进制计数法
%g 浮点数,e计数法
%G 浮点数,e计数法
%i 有符号十进制整数(与%d相同)
%o 无符号八进制数
%p 指针
%s 字符串
%u 无符号十进制整数
%x 无符号十六进制整数,使用十六进制数0F
%X 无符号十六进制整数,使用十六进制数0F
%% 打印一个百分号

使用printf()函数


// printf转换说明
#include<stdio.h>
#define PI 3.141593

int main(void)
{
    int number =7;
    float pies = 12.75;
    int cost = 7800;

    printf("The %d contestants ate %f berry pies.\n", number,
           pies);
    printf("The value of pi is %f.\n",PI);
    printf("Farewell! thou art too dear for my possessing,\n");
    printf("%c%d\n",'$',2*cost);

    return 0;
}

运行程序:

The 7 contestants ate 12.750000 berry pies.
The value of pi is 3.141593.
Farewell! thou art too dear for my possessing,
$15600

printf()函数的格式

printf(格式字符串,待打印项1,待打印项2(包括表达式)….);

e.g

printf("The %d contestants ate %f berry pies. \n",number,pies);

上面的语句中包含了两个转换说明。
如果想要打印%,使用%转换即可,也就是%%。
###printf()的转换说明修饰符
在%和转换字符之间插入修饰符可修饰转换说明。
https://blog.csdn.net/whmnirvana/article/details/54580407

printf()标记

标记 含义
- 待打印项左对齐
+ 有符号值为正则显示+,负数则加上-
空格 有符号值为正则显示一个空格,为负数则加上 -
# 把结果转换为另一种形式。如果是%o格式,则以0开始;如果是%x格式,则以0x开始,对于浮点,即使没有小数点后,也打印小数点字符,对于G和g个是防止后面的0被删除。
0 对于数值格式,用前导0代替空格填充字段宽度。对于整数格式,如果出现 - 标记或指定精度,则忽略该标记

程序4-7(test 字段宽度)

//字段宽度
#include<stdio.h>
#define RAGES 985
int main(void)
{
    printf("*%d*\n",RAGES);
    printf("*%2d*\n",RAGES);
    printf("*%10d*\n",RAGES);
    printf("*%-10d*\n",RAGES);

    return 0;
}

*985*
*985*
*       985*
*985       *

程序4-8(一些浮点数的修辞符的组合)

/* - floats -- 一些浮点型修辞符的组合*/
#include<stdio.h>

int main(void)
{
    const double RENT = 3852.99; //const变量,限定为常量的作用

    printf("*%f*\n", RENT);
    printf("*%e*\n", RENT); //默认小数点左边1位,右边6位,但是打印次数多!
    printf("*%4.2f*\n", RENT);
    printf("*%3.1f*\n", RENT); //控制后面打印的位数为1
    printf("*%10.3f*\n", RENT);//控制小数点后面打印位数为3
    printf("*%10.3E*\n", RENT); // 四舍五入
    printf("*%+4.2f*\n", RENT);
    printf("*%010.2f*\n", RENT);

    return 0;

}

*3852.990000*
*3.852990e+003*
*3852.99*
*3853.0*
*  3852.990*
*3.853E+003*
*+3852.99*
*0003852.99*

程序4-9(演示一些格式标记)

// 演示一些格式标记
#include<stdio.h>
int main(void)
{
    printf("%x %X %#x\n",31,31,31);  //%x打印十六进制数,#则标记十六进制数
    printf("**%d**% d**% d**\n", 42, 42, -42); //演示了空格的生成,负数则不产生
    printf("**%5d**%5.3d**%05d**%05.3d**\n", 6, 6, 6, 6);//这里使用了精度,前导0和精度一起出现0会被忽略

    return 0;
}

1f 1F 0x1f
**42** 42**-42**
**    6**  006**00006**  006**

程序4-10(字符串格式)

// stringf ---字符串格式
#include<stdio.h>
#define BLURB "Authentic imitation!"
int main(void)
{
    printf("[%2s]\n", BLURB);
    printf("[%24s]\n", BLURB);
    printf("[%24.5s]\n",BLURB);
    printf("[%-24.5s]\n",BLURB);

    return 0;
}

该程序输出如下:

[Authentic imitation!]
[    Authentic imitation!]
[                   Authe]
[Authe                   ]

转换说明的意义(就是不当的操作会出现问题)

转换说明把以二进制格式储存在计算机中的值转换成一系列的字符(字符串)形式以便显示。

转换(conversion) 是翻译说明,而不是原始值替换成转换后的值。无论如何,无论显示说明,值还是那个被储存在计算机里的二进制。

a.转换不匹配
(1)一些不匹配的整型转换
// 一些不匹配的整型转换
#include<stdio.h>
#define PAGES 336
#define WORDS 65618
int main()

{
    short num = PAGES;
    short mnum = -PAGES;

    printf("num as short and unsigned short: %hd %hu\n",num ,num);
    printf("-num as short and unsigned short: %hd %hu\n",mnum, mnum);
    printf("num as int and char: %d %c\n",num,num);
    printf("WORDS as int , short , and char: %d %hd %c \n",WORDS,WORDS ,WORDS);

    return 0;

}

num as short and unsigned short: 336 336
-num as short and unsigned short: -336 65200
num as int and char: 336 P
WORDS as int , short , and char: 65618 82 R  8265618除以65535的余数
(2) 不匹配的浮点型转换
/* loatcnv  -- 不匹配的浮点型转换*/
#include <stdio.h>

int main(void)
{
    float n1 =3.0;
    double n2 = 3.0;
    long n3 = 20000000000;
    long n4 = 12345567890;

    printf("%.le %.le %.le %.le\n",n1,n2,n3,n4);
    printf("%ld %ld\n",n3,n4);
    printf("%ld %ld %ld %ld\n",n1,n2,n3,n4);

    return 0;
}

3e+000 3e+000 -6e+153 7e+264
-1474836480 -539333998
0 1074266112 0 1074266112
b.Printf()的返回值
(1)printf()返回值

// printf()返回值

#include<stdio.h>
int main(void)
{
    int bph2o = 212;
    int rv;

    rv = printf("%d F is water 's boiling point. \n",bph2o); //将printf()的返回值赋值给rv。
    printf("The printf() function printed %d characters.\n",
           rv);

    return 0;
}

212 F is water 's boiling point.
The printf() function printed 34 characters.
c.打印较长的字符串

有时,printf()语句太长,在屏幕上不方便阅读,所以需要写成多行。
有几点要注意的是断行不能在“”之间断行,要在待打印项中间的逗号后面换行。
程序 - 打印较长的字符串

// longstrg  - -- 打印较长的字符串
#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");   /* ANSI C*/

    return 0;
}

Here's one way to print a long string.
Here's another way to print a long string.
Here's the newest way to print a long string.

方法一:使用多个printf语句。
方法二:用反斜杠(\)和 Enter 键组合。
方法三: ANSI C 引入了字符串连接,在两个双引号括起来的字符串之间用空白隔开
例如:

printf("Hello,young");
printf("Hello"      "young");
printf("Hello"
"young");

以上三个是等效的。

使用scanf()

scanf()与printf()相反,是输入函数,是C库里面通用的一个函数。键盘输入的都是文本,因为键盘只能输入文本字符,字母、数字、标点符号。

scanf()把输入的字符串转为整数、浮点数、字符、字符串。
printf()把整数、浮点数、字符、字符串转换为在屏幕上显示的文本。

它们两个的格式类似,也是用格式字符串和参数列表。scanf()使用的是指向变量指针,这里不需要知道指针,知道下面两个规则。

  • scanf()读取基本变量类型的值,在变量名前面加&;

  • scanf()把字符串读入字符数组中,不要使用&;
    程序 使用&的规则

    // input --何时使用&
    #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;
    }
    

Enter your age, assets , and favorite pet.
123
323
是的
123 $323.00 是的

在输入的同时可以输入换行符、空格或制表符分成两行。
唯一不同的是%c,会读取每个字符,包括空格、制表符、换行符

scanf()的转换说明
转换说明 含义
%c 把输入解释成字符
%d 把输入解释成十进制整数
%e、%f、%g、%a 把输入解释成浮点数
%E、%F、%G、%A 把输入解释成浮点数
%i 把输入解释成十进制整数
%o 把输入解释成有符号八进制整数
%p 把输入解释成指针(地址)
%s 把输入解释成字符串。从第一个非空白字符开始,到下一个字符串之前都是输入。
%u 把输入解释成无符号十进制数
%x、%X 把输入解释成有符号十六进制数
scanf()转换说明
转换说明 含义
* 抑制赋值
数字 最大字段宽度。达到最大字段宽度处,或遇到空白字符停止
hh 把整数作为signed cahr或unsigned char 类型读取
ll 把整数作为long long 或unsigned long long类型读取
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类型
z 在整形转换说明后面时,表明sizeof的返回类型
t 在整形转换后面时,表明使用表示两个指针差值的类型
1.从scanf()角度看输入

C语言还有其它的输入函数,如getchar()、fgets()。但是这两个函数更适合处理一些特殊的情况,scanf()函数可以读取整数、小数、字符和字符串。

2.格式字符串中的普通字符

scanf()函数允许普通字符放在格式字符串中。

3.scanf()的返回值

scanf()函数返回成功读取的项数。

printf()和scanf()的*修饰符

printf和scanf都使用*修辞符,但用法不一样,如果不想预先设定指定字宽,就可以使用*来代替。
printf()*程序

/* arwid -- 使用变宽输入字段 */
#include<stdio.h>
int main(void)
{
    unsigned width,precision;
    int number = 256;
    double weight = 242.5;

    printf("Enter a field width:\n");
    scanf("%d",&width);
    printf("The number is :%*d:\n",width , number);
    printf("Now enter a width and a precision:\n");
    scanf("%d %d",&width, &precision);
    printf("Weight = %*.*f\n",width,precision, weight);
    printf("Done!\n");

    return 0;
}

Enter a field width:
2
The number is :256:
Now enter a width and a precision:
12 2
Weight =       242.50
Done!

scanf()*程序

// 通过输入中的两个整数
#include<stdio.h>
int main(void)
{
    int n;

    printf("Please enter three integers:\n");
    scanf("%*d %*d %d", &n);
    printf("The last integer was %d\n",n);

    return 0;
}

Please enter three integers:
123 1235 666
The last integer was 666

》在读取特定的内容时,逃过功能很有效。*放在%和转换字符之间时,会使得scanf()跳过相应的输出项。

printf()的用法提示

printf("%d %d %d\n", val1,val2 ,val3);

打印出来的数字会参差不齐,所以使用__足够大__的固定字段宽度可以让输出整齐美观。

printf("%9d %9d %9d\n", val1, val2 ,val3);

这样就美观了。
程序 :printf用法,更美观的输出

// printf用法,更美观的输出
#include<stdio.h>
#define a 234
#define b 12
#define c 1
int add(void);
int main(void)
{
    int one , two , thr;

    one = 1212;
    two = 2312;
    thr = 456243;

    printf("%d %d %d\n",one,two,thr);
    printf("%d %d %d\n",a , b ,c);
    add();
    printf("%9d %9d %9d\n",one,two,thr);
    printf("%9d %9d %9d\n",a , b ,c);
    return 0;
}
int add(void)
{
    int w1,w2, w3;
    w1 = 12;
    w2 = 3223;
    w3 = 4523423;

    printf("%d %d %d\n",w1,w2,w3);

    printf("%9d %9d %9d\n",w1,w2,w3);
}

1212 2312 456243
234 12 1
12 3223 4523423
       12      3223   4523423
     1212      2312    456243
      234        12         1
本地化设置

就是有些地方的小数中间不是用点,而是用都好,比如荷兰,所以C语言对这些特殊的地方提供了本地的语言环境,所以这个我们是比较常规的,不同考虑。

关键概念

C语言用char类型表示__单个字符__,用字符串表示__字符序列__.字符串常量是一种字符串形式,不管是存储在字符串数组还是字符常量中,都以一个NULL结尾。

在程序中,尽量使用明示常量,不管用#define也好,还是用const限定变量都可以。提高程序的可读性和可维护性。

C语言中,标准输入函数和输出函数I/O都使用一个相同,scanf和printf。其重点都是转换说明必须与后序参数中的值相匹配。例如,int转换为%d与一个浮点值匹配会产生奇怪的结果。必须格外小心。

小结

字符串是一系列被视为一个处理单元的字符。字符串是以NULL结尾的一系列字符。
可以把字符串存储在字符数组里。数组是一系列同类型的项或元素。

字符串常量是用双引号括起来的字符序列。

scanf()函数可用于获得字符串的长度。%s可读取一个单词

C预处理器为预处理器指令,查找源代码程序,并在编译之前处理它们,根据include指定把另一个文件中的内容添加到该指定所在的位置。#define指令可以创建明示常量,limits.h和float.h头文件用#define定义了一组表示整数和浮点型不同属性的符号常量。另外还可以使用const限定符创建定义不可修改的只读变量。

printf()和scanf()函数对输入和输出提供多种支持。两个函数都使用格式字符串,其中包括转换说明表明待读取或待打印数据项的数量和类型。另外,可以使用转换说明控制输出的外观:宽度、小数点、字段的布局。


作业,本人不喜欢做作业,但是很可以的是有答案,嘻嘻

1.请输入名和姓(根据英文的书效果,中间又一个空格),会发生说明情况,为什么?

#include<stdio.h>
#include<string.h>      //提供trlen()函数的原型

#define DENSITY 62.4    //人体密度 density
int main()
{
   float weight, volume;
   int size, letters;
   char name[40];          //name是一个可容纳40个字符的数组,但是只能储存39个,最后一个是空NULL或者\0

   printf("Hi! What's your first name?\n",name);
   /*%s转换说明来处理字符串的输入和输出,没有&*/
   scanf("%s",name);
   printf("%s,what's your weight in pounds?\n",name);
   scanf("%f",&weight);
   size = sizeof name;
   volume = weight / DENSITY;
   printf("Well, %s, your volume is %2.2f cubic feet.\n",name,volume);
   printf("Also,your first name has %d letters,\n",letters);
   printf("and we have %d bytes to store it. \n",size);

   return 0;
}

Hi! What's your first name?
ge yun
ge,what's your weight in pounds?    //只出现了ge,yu没有打印。
Well, ge, your volume is 0.00 cubic feet.
Also,your first name has 52 letters,
and we have 40 bytes to store it.

程序只能读到名,而姓还在缓冲区,下一条scanf输入缓冲区查找时,从上次读入结束的地方开始读取,这样就把留在缓冲区的姓作为体重来读取,导致scanf()读取失败。另一方面,如果输入lasha 134,那么程序会把134作为用户体重。

2.在C中如何输出双引号

转义就行了

3.找错误

define B booboo
define X 10
main(int)
{
  int age;
  cahr name;
  printf("Please enter your first name.");
  scanf("%s",name);
  printf("All right, %c ,what's your age?\n",name);
  xp = age+ X;
  printf("That's a %s! You must be at least %d\n",name);
  rerun 0;
}

文章作者: Enomothem
版权声明: 本博客所有文章除特别声明外,均采用 CC BY 4.0 许可协议。转载请注明来源 Enomothem !
  目录