.格式化输入输出[1-1.cpp]
.printf
.% [ flags ][width][.prec][hIL]type 例如:%d
.scanf
.%[flags]type
.% [ flags ][width][.prec][hIL]type
Flags | 含义 |
---|---|
- | 左对齐 |
+ | 在前面放+或- |
(space) | 正数留空 |
0 | 0填充 |
width或prec | 含义 |
---|---|
number | 最小字符数 |
* | 下一个参数是字符数 |
.number | 小数点后面的位数 |
.* | 下一个参数是小数点后的位数 |
例如:printf("%*d\n", 4, 123);
此时,4会被填入*处,可以用变量len来规定输出字符的
长度,增加了输出的灵活性
例:printf("%*d\n", len, 123); //len的值会被填入到*处
类型修饰 | 含义 |
---|---|
hh | 单个字节 |
h | short |
l | long |
ll | long long |
L | long double |
type | 用于 |
---|---|
i或d | int |
u | unsigned int |
o | 八进制 |
x | 十六进制 |
X | 字母大写的十六进制 |
f/F | float, 6 |
e/E | 指数 |
g | float |
G | float |
a/A | 十六进制浮点 |
c | char |
s | 字符串 |
p | 指针 |
n | 读入/写出的个数 |
.程序1-1.cpp:
#include <stdio.h>
int main(int argc, char const *argv[])
{
printf("%9d\n", 123);
printf("%-9d\n", 123);
printf("%9.2f\n", 123.0);
printf("%*d\n", 4,123); //printf("%*d\n", len,123);
printf("%hhd\n", 12345); //12345 = 0x3039; The last byte is 39, 0x39 = 57
int num;
printf("%9dtty%n\n", 1234, &num); //%n: Count the number of bytes of "%n".
printf("num=%d\n", num);
return 0;
}
.运行结果:
.scanf:%[flag]type.
flag | 含义 |
---|---|
* | 跳过 |
hh | char |
h | short |
l | long double |
ll | long long |
L | long double |
数字 | 最大的字符数 |
.%*跳过[1-2.cpp]
#include <stdio.h>
int main(int argc, char const *argv[])
{
int num;
scanf("%*d%d", &num);
printf("%d\n", num);
return 0;
}
.运行结果:
type | 用于 |
---|---|
d | int |
i | 整数,可能为十六进制或八进制 |
u | unsigned int |
0 | 八进制 |
x | 十六进制 |
a,e,f,g | float |
c | char |
s | 字符串(单词) |
[…] | 所有允许的字符 |
p | 指针 |
.%i [1-3.cpp]
#include <stdio.h>
int main(int argc, char const *argv[])
{
int num;
scanf("%i", &num);
printf("%d\n", num);
return 0;
}
.十六进制运行结果:
.八进制运行结果:
.printf和scanf的返回值[1-4.cpp]
.读入的项目数[scanf返回读得变量数]
.输出的字符数[别忘了末尾的"\0"]
.在要求严格的程序中,应该判断每次调用scanf或printf
的返回值,从而了解程序运行过程中是否存在问题
#include <stdio.h>
int main(int argc, char const *argv[])
{
int num1;
int num2;
int i1 = scanf("%i%i", &num1, &num2);
int i2 = printf("num1=%d, num2=%d\n", num1, num2);
printf("i1=%d\ti2=%d\n", i1, i2);
return 0;
}
.运行结果:
.文件输入输出
.如果我们已经写好了一个程序,它是通过标准输入输出
printf/scanf来读写数据的,我们可以将输出写到文件中去
也可以让这个程序从文件中读数据
.用>和<做重定向[可以通过Linux命令行来做]
.程序运行中的重定向,用">"将程序输出结果写到
文件中;用"<"程序从文件中读取输入
.文件输入输出的一般方式(FILE):
.FILE* fopen(const char* restrict path, const charrestrict
mode)
.int fclose(FILE,…)
.fscanf(FILE*,…)
.fprintf(FILE*,…)
.打开文件的标准代码
.FILE* fp = fopen(“file”, “r”); //如果每打开返回NULL
if( fp )
{
fscanf(fp, …);
fclose( fp );
}
else
{
…
}
.fopen
r | 打开只读 |
---|---|
r+ | 打开读写,从文件头开始 |
w | 打开只写,如果不存在则新建,如果存在则清空 |
w+ | 打开读写,如果不存在则新建,如果存在则清空 |
a | 打开追加.如果不存在则新建,如果存在则从文件尾开始 |
…x | 只新建,如果文件已经存在则不能打开 |
.二进制文件
.其实所有二进制文件最终都是二进制的
.文本文件无非是用最简单的方式可以读写的文件
.more
.tail
.vi
.而二进制文件是需要专门的程序来读写的文件
.文本文件的输入输出是格式化,可能经过转码
.文本文件vs二进制文件
.Linux 喜欢用文本文件来做数据存储和程序设置
.交互式终端的出现使得人们喜欢用文本和计算机进行
交互.
.Linux 的Shell提供了一些读写文本的小程序
.Windows喜欢用二进制文件
.Dos是草根文化,并不继承和熟悉Linux文化
.PC刚开始的时候能力有限,Dos的能力更有限,二进
更接近底层
.程序为什么要文件
.配置
.Uinux 用文本,Windows用注册表
.数据
.稍微有点量的数据都放在数据库了
.媒体
.只能用二进制文件
.现实是,程序通过第三方库来读写文件,很少直接读
写二进制文件了
.二进制文件的读写[1-6.cpp]
.size_t fread(void* restrict ptr, size_t size, size_t
nitems, FILE* restrict stream);
.size_t fwrite(void* const restrict ptr, size_t size,
size_t nitems, FILE* restrict stream);
.注意:FILE指针是最后一个参数
.返回的是成功读写的字节数
.nitems参数:
.因为二进制文件的读写一般都是通过对一个结构变
量的操作来进行的
.于是nitems就是用来说明这次读写几个结构变量
.student.h
#ifndef __STUDENT_H__
#define __STUDENT_H__
#define STR_LEN 20
//const int STR_LEN = 20;
typedef struct _student
{
char name[STR_LEN];
int gender;
int age;
}Student;
#endif
.1-6.cpp
#include <stdio.h>
#include "student.h"
void getList(Student aStu[], int number);
int save(Student aStu[], int number);
int main(int argc, char const *argv[])
{
int number = 0;
printf("Please input number of student!\n");
scanf("%d", &number);
Student aStu[number];
getList(aStu, number);
if(save( aStu, number) )
{
printf("Saved!\n");
}else{
printf("Not saved!\n");
}
return 0;
}
void getList(Student aStu[], int number)
{
char format[STR_LEN];
sprintf(format, "%%%ds", STR_LEN-1); //input to a string
int i;
for( i=0; i<number; i++)
{
printf("The %d's student: \n", i);
printf("\tname: ");
scanf(format, &aStu[i].name);
printf("\tsex (0-Men, 1-Women, 2-Others) : ");
scanf("%d", &aStu[i].gender);
printf("\tage: ");
scanf("%d", &aStu[i].age);
}
}
int save(Student aStu[], int number)
{
int ret = -1;
FILE* fp = fopen("student.data", "w");
if( fp )
{
ret = fwrite(aStu, sizeof(Student), number, fp);
fclose(fp);
}
return ret == number;
}
.运行结果:
.在文件中定位[1-7.cpp]
.long ftell(FILE* stream);
.int fseek(FILE* stream, long offset, int whence);
.SEEK_SET:重头开始
.SEEK_CUR:从当前位置开始
.SEEK_END:从尾开始(倒过来)
.student.h
#ifndef __STUDENT_H__
#define __STUDENT_H__
#define STR_LEN 20
//const int STR_LEN = 20;
typedef struct _student
{
char name[STR_LEN];
int gender;
int age;
}Student;
#endif
.1-7.cpp
#include <stdio.h>
#include "student.h"
void read(FILE* fp, int index);
int main(int argc, char const *argv[])
{
FILE* fp = fopen("student.data", "r");
if( fp )
{
fseek(fp, 0L, SEEK_END);
long size = ftell(fp);
int number = size / sizeof(Student);
int index = 0;
printf("There have %d datas, which one do you want: ", number);
scanf("%d", &index);
read(fp, index-1);
fclose(fp);
}
return 0;
}
void read(FILE* fp, int index)
{
fseek(fp, index*sizeof(Student), SEEK_SET);
Student stu;
if( fread(&stu, sizeof(Student), 1, fp) == 1)
{
printf("The %d's student:\n", index+1);
printf("\tname: %s\n", stu.name);
printf("\tsex: ");
switch( stu.gender)
{
case 0: printf("Men\n"); break;
case 1: printf("Women\n"); break;
case 2: printf("Others\n"); break;
}
printf("\tage: %d\n", stu.age);
}
}
.运行结果: