读书笔记之C Primer Plus 4

为什么阅读《C Primer Plus》第六版

准备好好研究下redis源码,但是很久没用c语言写代码了,平时工作主要用java和js。
所以准备重新阅读学习下c语言经典书籍:C Primer Plus。
更好的阅读redis源码。


第6章和第7章 循环 分支和跳转

第8章 字符输入/输出和输入验证

单字符I/O getchar()和putchar()

/* echo.c -- 重复输入 */
#include <stdio.h>
int main(void)
{
    char ch;
    while ((ch = getchar()) != '#')
        putchar(ch);
    return 0;
}
  • ANSI C标准: getchar,putchar -> stdio.h
  • getchar和putchar都不是真正的函数,是宏。

缓冲区

为什么有缓冲区?
一个块进行传输比逐个发送字符节约时间,打错还可修正,按下Enter键,才是真正的输出。

  • 完全缓冲IO: 缓冲区被填满才刷新缓冲区,通常出现在文件输入中
  • 行缓冲IO: 出现换行符时刷新缓冲区

结束符

#define EOF (-1)

判断是否文件结尾,检测返回EOF,如果是EOF表示是文件结尾。
大部分系统有办法通过键盘模拟文件结尾条件EOF

注意以下几点:

  • 不用定义EOF,stdio.h统一定义
  • 不用担心EOF的实际值。
  • ch是整数不会影响putchar(),该函数仍然会打印等价的字符。
  • 模拟输入EOF字符,不能是-1,大部分unix和linux是Ctrl+D,还有的是Ctrl+Z

重定向和文件

<符合 重定向输入 >符号重定向输出

  • ./echo < my.txt my.txt重定向为输入
  • ./echo > my.log my.log重定向输出

组合重定向:./echo < my.txt > my.log
顺序无关,但是文件名不能相同。

总之:

  • 使用重定向运算符不能读取多个文件的输入,也不能输出到多个文件。
  • 重定向运算符连接一个可执行程序和一个数据文件,不能用于两个数据文件之间,也不能两个程序之间。
  • 文件名和程序名之间的空格不是必须的。

输入验证

实际应用中,用户经常输入错误,需要做验证。
scanf返回成功读取项的个数。
scanf(“%ld”,&n) == 1 判断用户输入一个整数时是否正确。

第9章 函数

如何组织程序?C的设计思想是,把函数用作构件块。

首先,什么是函数?函数是完成特定任务的独立程序代码单元。
语法规则定义了函数的结构和使用方式。虽然C中的函数和其他语言中的函数、子程序、过程作用相同,但是细节上略有不同。
一些函数执行某些动作,如printf()把数据打印到屏幕上;
一些函数找出一个值供程序使用,如strlen()把指定字符串的长度返回给程序。
一般而言,函数可以同时具备以上两种功能。

创建简单函数

/* lethead1.c */
#include <stdio.h>
#define NAME "GIGATHINK, INC."
#define ADDRESS "101 Megabuck Plaza"
#define PLACE "Megapolis, CA 94904"
#define WIDTH 40

void starbar(void);  /* 函数原型 */

int main(void)
{
     starbar();
     printf("%s\n", NAME);
     printf("%s\n", ADDRESS);
     printf("%s\n", PLACE);
     starbar();       /* 使用函数 */

     return 0;
}

void starbar(void)   /* 定义函数    */
{
     int count;
     for (count = 1; count <= WIDTH; count++)
          putchar('*');
     putchar('\n');
}

程序输出

****************************************
GIGATHINK, INC.
101 Megabuck Plaza
Megapolis, CA 94904
****************************************
  • 程序在3处使用了starbar标识符:函数原型告诉编译器函数starbar()的类型;函数调用表明在此处执行函数;函数定义明确地指定了函数要做什么。
  • 函数和变量一样,有多种类型。
  • 一般而言,函数原型指明了函数的返回值类型和函数接受的参数类型。这些信息称为该函数的签名。对于starbar()函数而言,其签名是该函数没有返回值,没有参数。
  • 程序把starbar()原型置于main()的前面。当然,也可以放在main()里面的声明变量处。放在哪个位置都可以。
  • 函数头中的starbar()后面没有分号,告诉编译器这是定义starbar(),而不是调用函数或声明函数原型。
  • 程序把starbar()和main()放在一个文件中。也可以把它们分别放在两个文件中。如果把函数放在一个单独的文件中,要把#define和#include指令也放入该文件。
  • starbar()函数中的变量count是局部变量(local variable),意思是该变量只属于starbar()函数。可以在程序中的其他地方(包括main()中)使用count,这不会引起名称冲突,它们是同名的不同变量。

函数参数

void show_n_char(char ch, int num)

该行告知编译器show_n_char()使用两个参数ch和num,ch是char类型,num是int类型。这两个变量被称为形式参数,简称形参。和定义在函数中变量一样,形式参数也是局部变量,属该函数私有。这意味着在其他函数中使用同名变量不会引起名称冲突。每次调用函数,就会给这些变量赋值。

在使用函数之前,要用ANSI C形式声明函数原型,不过可以省略变量名

void show_n_char(char, int);

调用函数

show_n_char(SPACE, 12);

被调函数不知道也不关心传入的数值是来自常量、变量还是一般表达式。
因为被调函数使用的值是从主调函数中拷贝而来,所以无论被调函数对拷贝数据进行什么操作,都不会影响主调函数中的原始数据

使用return从函数中返回值

编译多源代码文件的程序

  • 下面的命令将编译两个文件并生成一个名为a.out的可执行文件
cc file1.c file2.c
  • 如果后来改动了file1.c,而file2.c不变,可以使用以下命令编译第1个文件,并与第2个文件的目标代码合并
cc file1.c file2.o

使用头文件

文件的头文件定义例子:

/* hotel.h -- 符号常量和 hotel.c 中所有函数的原型 */
#define QUIT       5
#define HOTEL1   180.00
#define HOTEL2   225.00
#define HOTEL3   255.00
#define HOTEL4   355.00
#define DISCOUNT   0.95
#define STARS "**********************************"

// 显示选择列表
int menu(void);

// 返回预订天数
int getnights(void);

// 根据费率、入住天数计算费用
// 并显示结果
void showprice(double rate, int nights);

指针简介

什么是指针?从根本上看,指针是一个值为内存地址的变量(或数据对象)。
假设一个指针变量名是ptr,可以编写如下语句:

ptr = &bah;// 把bah的地址赋给ptr

现在ptr的值是bah的地址。

nurse = 22;
ptr = &nurse;  // 指向nurse的指针
val = *ptr;    // 把ptr指向的地址上的值赋给val

声明指针

int * pi;        // pi是指向int类型变量的指针
char * pc;        // pc是指向char类型变量的指针
float * pf, * pg;    // pf、pg都是指向float类型变量的指针

使用指针在函数间通信

/* swap3.c -- 使用指针解决交换函数的问题 */
#include <stdio.h>
void interchange(int * u, int * v);

int main(void)
{
     int x = 5, y = 10;
     printf("Originally x = %d and y = %d.\n", x, y);
     interchange(&x, &y);    // 把地址发送给函数
     printf("Now x = %d and y = %d.\n", x, y);

     return 0;
}

void interchange(int * u, int * v)
{
     int temp;
     temp = *u;    // temp获得 u 所指向对象的值
     *u = *v;
     *v = temp;
}

输出

Originally x = 5 and y = 10.
Now x = 10 and y = 5.
  • interchange(&x, &y); 该函数传递的不是x和y的值,而是它们的地址。
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

余很多之很多

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值