int a[2][3] = {1,2,3,4,5,6};
a[0] a[0]+1 a[0]+2
| | |
v v v
a->1 2 3
a+1->4 5 6
a的类型:int (*)[3]
a[0]的类型:int*
对于以上二维数组以下表达式的值是相等的:
a+i
*(a+i)
a[i]
&a[i]
&a[i][0]
-------------
x[y] = *(x+y)
a[i][j]
= *(a[i]+j)
= *(*(a+i)+j)
六、多级指针
二级指针:指向一级指针的指针,其中存放一个一级指针的地址。
int a, b, c;
int* pa[] = {&a, &b, &c};
char* pc[] = {"hello", "world", "tarena"};
int** ppa = pa;
七、空指针(void*)
1.代表任意类型的指针。
2.一切类型的指针都可以隐式转换为空指针。
3.对空指针不能解引用。
4.空指针支持计算,但是统一按单字节处理。
八、动态内存分配与释放
#include <stdlib.h>
void* malloc (
size_t size // 预分配字节数
);
成功返回所分配内存的起始地址,失败返回NULL。不初始化。
void* calloc (
size_t nmemb, // 元素数
size_t size // 元素字节数
);
成功返回所分配内存的起始地址,失败返回NULL。初始化为0。
所有通过动态内存分配所得到内存都要通过free()函数释放。
void free (
void* ptr // 内存地址
);
void* realloc (
void* ptr, // 原地址
size_t size // 新字节数
);
成功返回调整后的内存地址,失败返回NULL。新增部分不做初始化。
如果ptr为NULL,则与malloc()等效。
如果size为0,则与free()等效。
可能会分配新的内存空间,如果发生这种情况,原内存会自动释放,其内容会拷贝到新内存中,但是如果分配失败,原内存不会释放。
char* p = (char*)malloc (10);
char* p2 = realloc (p, 20);
if (p2)
p = p2;
else {
free (p);
return -1;
}
举例:录入多行文本,每行不超过255个字符,行数不限,输入!表示输入结束,将之前输入的所有内容拼成一个字符串输出。
输入> 达内
输入> 科技
输入> 有限公司
输入> !
输出> 达内科技有限公司
九、函数指针及其解引用
1.用指针存储代码区中的函数地址。所有的函数都有地址,而函数名实际上就是该函数的符号地址。
2.定义语法
函数:返回类型 函数名 (形参表) {函数体;}
函数指针:
返回类型 (*函数指针名) (形参表);
例如:
int foo (int a, double b){...}
int bar (int a, double b)
{...}
int (*pfoo) (int, double) = foo;
pfoo = bar;
3.解引用语法
函数指针名 (实参表);
pfoo (10, 3.14); // 调用bar
----------------
pfoo = &bar;
(*pfoo) (10, 3.14);
第十二课 IO流与标准库
一、IO流的打开和关闭
FILE* fopen (
const char* filename, //文件路径
const char* mode // 打开模式
);
打开模式:
r: 读
w: 写
a: 追加
r+: 读写,文件必须存在,从头开始
w+: 写读,文件不存在就创建,文件存在就清空
a+: 读写,文件不存在就创建,文件存在就追加
b: 二进制方式
UNIX/Linux:二进制方式作用不大
Windows:二进制方式,对读写内容不做任何转换。非二进制方式,写入\n,实际写入\r\n,文件中\r\n,读到的\n。
返回值是IO流结构体指针,用户调用其他IO流函数。
int fclose (
FILE* fp // fopen的返回值
);
成功返回0,否则返回EOF。
进程一启动,以下标准IO流是默认打开的:
stdout: 标准输出
stdin: 标准输入
stderr: 标准出错
二、格式化IO
int fprintf (
FILE* stream, // IO流指针
const char* format,// 格式字符串
... // 输出数据项
);
printf(...)实际就是fprintf (stdout, ...)
格式字符串:
%[标志][宽度][.精度][h|l|ll]类型符
标志:
- 左对齐
+ 输出正负号
# 输出进制标识
0 用0填充
宽度.精度:123.34,宽度6,精度2,%6.2f
h short
l long/double
ll long long
类型符:
d 十进制整数
c 字符
s 空字符结尾的字符串
f 浮点数
x/X 十六进制整数
o 八进制整数
p 地址(十六进制)
u 无符号十进制整数
g 浮点数(自动选择最短形式)
e 浮点数(科学计数法)
int fscanf (
FILE* stream, // IO流指针
const char* format, // 格式字符串
... // 地址表
);
1)以空白字符(空格、制表、换行)作为数据分隔符。
2)模式匹配:根据格式化字符串的模式进行匹配,从中提取数据。
3)禁止赋值:*
4)字符集表示:只读取某个特定字符集中的字符,只要遇到字符集以外的字符即刻返回。
三、非格式化IO
int fputc (
int c, // 字符
FILE* stream // IO流指针
);
成功返回c,失败返回EOF。
int fgetc (
FILE* stream // IO流指针
);
成功返回读到的字符,失败或者遇到文件尾返回EOF。
四、二进制IO
size_t fread (
void* buf, // 缓冲区指针
size_t size, // 期望读取的数据单元字节数
size_t count, // 期望读取的数据单元数
FILE* stream // IO流指针
);
成功返回实际读取的数组单元数。失败或遇到文件尾返回0。
size_t fwrite (
void* buf, // 缓冲区指针
size_t size, // 期望写入的数据单元字节数
size_t count, // 期望写入的数据单元数
FILE* stream // IO流指针
);
成功返回实际写入的数据单元数,失败返回0。
五、流位置与随机访问
六、可变参数
七、日期时间
八、实用工具
#include <stdio.h>
void foo (int* c, int size) {
}
void bar (int (*a)[3], int size) {
}
int main (void) {
int a[2][3] = {1,2,3,4,5,6};
// 降维
int* b = (int*)a;
int i, j;
for (i = 0; i < 6; i++)
printf ("%d ", b[i]/* *(b+i) */);
printf ("\n");
int c[6] = {1,2,3,4,5,6};
// 升维
int (*d)[2] = (int (*)[2])c;
for (i = 0; i < 3; i++) {
for (j = 0; j < 2; j++)
printf ("%d ", d[i][j]/* *(*(d+i)+j) */);
printf ("\n");
}
foo (c, sizeof (c) / sizeof (c[0]));
bar (a, sizeof (a) / sizeof (a[0]));
return 0;
}
#include <stdio.h>
#include <stdlib.h>
double g_balance = 0.0;
double g_rate = 0.01;
void clean (void) {
scanf ("%*[^\n]");
scanf ("%*c");
}
int menu (void) {
printf ("--------\n");
printf ("迷你银行\n");
printf ("--------\n");
printf ("[1] 清户\n");
printf ("[2] 存款\n");
printf ("[3] 取款\n");
printf ("[4] 查询\n");
printf ("[5] 结息\n");
printf ("[6] 调息\n");
printf ("[0] 退出\n");
printf ("--------\n");
printf ("请选择:");
int sel = -1;
scanf ("%d", &sel);
clean ();
return sel;
}
void query (void) {
printf ("当前余额:%.2lf\n", g_balance);
}
void clear (void) {
g_balance = 0;
query ();
}
void save (void) {
printf ("存款金额:");
double save;
scanf ("%lf", &save);
clean ();
g_balance += save;
query ();
}
void withdraw (void) {
printf ("取款金额:");
double withdraw;
scanf ("%lf", &withdraw);
clean ();
if (g_balance < withdraw)
printf ("余额不足!\n");
else {
g_balance -= withdraw;
query ();
}
}
void settle (void) {
g_balance *= (1 + g_rate);
query ();
}
void adjust (void) {
printf ("当前利率:%.2lf\n", g_rate);
printf ("存款利率:");
scanf ("%lf", &g_rate);
clean ();
}
void quit (void) {
printf ("再见!\n");
exit (0);
}
int main (void) {
void (*deal[]) (void) = {quit, clear, save, withdraw, query, settle, adjust};
for (;;) {
int sel = menu ();
if (sel >= 0 && sel < sizeof (deal) / sizeof (deal[0]))
deal[sel] ();
else
printf ("选择错误!\n");
}
return 0;
}
#include <stdio.h>
#include <string.h>
// 以二进制形式打印一个字节
void printb (char byte) {
size_t i;
for (i = 0; i < 8; i++)
printf ("%c", byte & 1<<7-i ? '1' : '0');
printf (" ");
}
// 以二进制形式打印一个内存块
void printm (void* buf, size_t size) {
size_t i;
for (i = 0; i < size; i++)
printb (((char*)buf)[i]);
printf ("\n");
}
int main (void) {
int a = 0x12345678;
printm (&a, sizeof (a));
double d = 3.14;
printm (&d, sizeof (d));
struct {
char name[128];
int age;
} student = {"张飞", 28};
printm (&student, sizeof (student));
return 0;
}
#include <stdio.h>
int main (void) {
FILE* fp = fopen ("fmt.txt", "w");
if (! fp) {
perror ("fopen");
return -1;
}
fprintf (fp, "[%-10d]\n", 12);
fprintf (fp, "[%+10d]\n", 12);
fprintf (fp, "[%6.2f]\n", 123.45678);
fprintf (fp, "[%x,%#X,%#o]\n", 15, 15, 15);
fprintf (fp, "[%e]\n", 0.000123456);
int i;
for (i = 1; i < 10; i++)
fprintf (fp, "%*c\n", i, '*');
fclose (fp);
fprintf (stdout, "hello world\n");
fprintf (stderr, "hello world\n");
fp = fopen ("fmt2.txt", "r");
if (! fp) {
perror ("fopen");
return -1;
}
int a;
double b;
char c[256], d[256];
fscanf (fp, "%d%lf%s%s", &a, &b, c, d);
printf ("[%d]\n[%lf]\n[%s]\n[%s]\n", a, b, c, d);
int e, f;
fscanf (fp, "%d+%d=%d", &a, &e, &f);
printf ("%d, %d, %d\n", a, e, f);
fscanf (fp, "%*d%d", &a);
printf ("%d\n", a);
fscanf (fp, "%s", c);
printf ("%s\n", c);
fscanf (fp, "%*c");
fscanf (fp, "%[a-z]%d", c, &a);
printf ("%s, %d\n", c, a);
fscanf (fp, "%*c");
fscanf (fp, "%[^a-c]%[a-z]", c, d);
printf ("%s, %s\n", c, d);
fclose (fp);
return 0;
}
#include <stdio.h>
int add (int a, int b) {
return a + b;
}
int sub (int a, int b) {
return a - b;
}
int mul (int a, int b) {
return a * b;
}
int div (int a, int b) {
return a / b;
}
int mod (int a, int b) {
return a % b;
}
int cal (int a, int b, int (*pfunc) (int, int)) {
return pfunc (a, b);
}
int main (void) {
int (*pfunc) (int, int);
pfunc = add;
printf ("%d\n", pfunc (10, 20));
pfunc = sub;
printf ("%d\n", pfunc (30, 10));
printf ("%d\n", cal (10, 20, add));
printf ("%d\n", cal (15, 2, div));
printf ("%d\n", cal (15, 2, mod));
return 0;
}
#include <stdio.h>
int main (void) {
FILE* fp1 = fopen ("get.txt", "r");
FILE* fp2 = fopen ("put.txt", "w");
int c;
for (;;) {
c = fgetc (fp1);
if (c == EOF)
break;
fputc (c, fp2);
}
fclose (fp2);
fclose (fp1);
return 0;
}
#include <stdio.h>
#include <stdlib.h>
int main (void) {
int* p = (int*)malloc (sizeof (int));
*p = 100;
printf ("%d\n", *p);
free (p);
//p = (int*)malloc (5 * sizeof (int));
p = (int*)calloc (5, sizeof (int));
int i;
for (i = 0; i < 5; i++)
p[i] = i;
for (i = 0; i < 5; i++)
printf ("%d ", p[i]);
printf ("\n");
free (p);
p = realloc (NULL, 1024 * sizeof (int));
if (! p) {
perror ("出错啦!");
return -1;
}
int* p2 = realloc (p, /*2048000*/0xFFFFFFFF * sizeof (int));
if (! p2) {
perror ("又出错啦!");
free (p);
return -1;
}
printf ("%p, %p\n", p, p2);
p = p2;
realloc (p, 0);
return 0;
}
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int main (void) {
char* full = NULL;
for (;;) {
printf ("输入> ");
char line[256];
gets (line);
if (! strcmp (line, "!"))
break;
if (! full) {
full = (char*)malloc ((strlen (line) + 1) * sizeof (char));
if (! full) {
perror ("错误> ");
return -1;
}
strcpy (full, line);
}
else {
char* new = (char*)realloc (full, (strlen (full) + strlen (line) + 1) * sizeof (char));
if (! new) {
perror ("错误> ");
free (full);
return -1;
}
strcat (full, line);
}
}
printf ("输出> %s\n", full);
free (full);
return 0;
}
#include <stdio.h>
void swap (int* a, int* b) {
int c = *a;
*a = *b;
*b = c;
}
void swap2 (const char** a, const char** b) {
const char* c = *a;
*a = *b;
*b = c;
}
int main (void) {
int a = 100;
int* p = &a;
int** pp = &p; // pp -> p -> a
printf ("a=%d,&a=%p\n", a, &a);
printf ("p=%p,&p=%p,*p=%d\n", p, &p, *p);
printf ("pp=%p,*pp=%p,**pp=%d\n", pp, *pp, **pp);
int x = 100, y = 200;
swap (&x, &y);
printf ("%d %d\n", x, y);
const char* pa = "hello";
const char* pb = "world";
printf ("%s %s\n", pa, pb);
swap2 (&pa, &pb);
printf ("%s %s\n", pa, pb);
return 0;
}
#include <stdio.h>
#include <string.h>
int intcmp (const void* pv1, const void* pv2) {
return *(const int*)pv2 - *(const int*)pv1;
}
int szcmp (const void* pv1, const void* pv2) {
const char** pp1 = (const char**)pv1;
const char** pp2 = (const char**)pv2;
return strcmp (*pp1, *pp2);
}
int main (void) {
int a[] = {13, 34, 9, 27, 77, 10, 64};
int len = sizeof (a) / sizeof (a[0]);
qsort (a, len, sizeof (a[0]), intcmp);
int i;
for (i = 0; i < len; i++)
printf ("%d ", a[i]);
printf ("\n");
const char* b[] = {"beijing", "chongqing", "shanghai", "tianjin", "jinan", "guangzhou", "hangzhou"};
len = sizeof (b) / sizeof (b[0]);
qsort (b, len, sizeof (b[0]), szcmp);
for (i = 0; i < len; i++)
printf ("%s ", b[i]);
printf ("\n");
return 0;
}
#include <stdio.h>
int main (void) {
char sz[256];
int a;
scanf ("%s", sz);
printf ("输入整数:");
char c;
scanf ("%c%d", &c, &a);
printf ("%s, [%c], %d\n", sz, c, a);
return 0;
}