前言
本来学JAVA学着学着听不懂什么叫空指针异常
上网上看感觉还是不够系统,趁着国庆重温C语言的经典C Primer Plus
这本书写的真的很细致,需要慢慢去消化吸收
纸上得来终觉浅,绝知此事要躬行
这句话看了好几遍了,我也写上去,很适合编程方向的学习
好了,开始啃书了
资源在这
第一章 初识C语言
一、C语言的起源
C 语言是一种高级语言,最初由 Dennis M. Ritchie [1] 为了开发一个操作系统而设计,最早在 1972 年在 DEC PDP-11 计算机上被首次实现。
二、C语言的应用
C 语言大量应用在需要直接硬件交互的场景。比如最近很多的物联网中的嵌入式设备,底层驱动,高性能计算,游戏后端服务,图形处理等等。
三、C语言的特点
- 代码简洁不繁琐;
- 具有良好的可移植性,代码与机器底层独立(相对于汇编语言而言);
- 属于中层编程语言(底层的为汇编语言等,高层的为 Java 语言等);
- 结构化语言;
- 丰富的程序库可以使用;
- 可以直接管理内存;
- 运行速度快;
- 提供了指针操作;
- 可以使用递归;
- 具有良好的扩展性。
四、编译的过程
着重介绍下编译,其他就是字面意思
编译是把自己编写的源代码转换成可执行的程序,可执行代码是用机器语言表示的代码。这种语言由数字码表示的指令组成。
五、编码机制
1.简述
C编程的基本策略是用程序把源码变成可执行文件来运行~
2.完成机制
C语言通过编译和链接两个步骤来完成这一过程,
编译器把源码转换为中间代码(目标代码文件),连接器把中间代码和库代码、启动代码(程序和OS之间的接口)进行合并,生成可执行文件
C语言通过这样分而治之的方法方便对程序进行模块化,可以独立编译单独的模块,稍后再用链接器合并已编译的模块。通过这种方式,如果只改变某个模块,不必全部重新编译一边,大大提高了效率!
六、在UNIX系统上使用C
一般用gcc编译器来编译
以上a.out就是可执行代码
七、一些OS
1.UNIX系统
UNIX操作系统,当时的电信业巨头AT&T(美国电报电话公司)的贝尔实验室开发的操作系统。 它是一个多用户、多任务操作系统,可以运行在大量不同种类的硬件平台上。
2.Linux
Linux是一个开源、流行、类似于UNIX的OS,Linux实际上只是一个内核,我们可以获得内核的源代码,编译并安装它,然后获得并安装许多其他自由发布的软件,从而完成一个完整的Linux系统的安装。
通常这样安装所得的系统称为Linux系统,系统中大多数的工具都来自于自由软件基金会的GNU项目。自己从源代码创建Linux系统比较麻烦,所以很多人制作了准备好Linux发行版(通常称为flavor),可以通过U盘和CD进行安装,这些发行版不仅包含Linux内核,还会装载一些编程工具和应用程序,一般都会装载一个X视窗系统。
著名的商业Linux发行版 Red Hat Enterprise Linux、Fedora、Novell SuSE Linux 著名的免费的Linux发行版 openSUSE变体、Ubuntu Linux、Slackware、Gentoo、Debian GNU/Linux。
3.GNU项目和自由软件基金会
自由软件基金会(Free Software Foundation) 由Richard Stallman创立,也是Emacs, GCC, GDB的开发者,GNU项目由他发起,这个项目的宗旨是试图创建一个与UNIX系统兼容,并不受UNIX名字和源代码私有权限制的操作系统和开发环境。
GNU项目软件 GCC:GNU编译器集,它包括GNU C编译器。 G++:C++编译器,是GCC的一部分。 GDB:源代码级调试器。 GNU make:UNIX make兼容的语法分析程序生成器。 bash:命令解释器(shell) GNU Emacs:文本编辑器及环境。
4.Windows
就是我们常用的OS,在Windows开发需要借助IDE(集成开发环境)
常用的工具是Mirc Visual Stdio Express
个人比较喜欢用的是Vscode
八、复习题和小结
C语言是编译型语言。C编译器和链接器是把C语言源代码转化成可执行代码的程序
1.对编程而言,可移植性意味着什么?
完美的可移植程序是,其源代码无需修改就可以在不同计算机OS上成功编译
2.解释源代码文件、目标代码文件和可执行文件有什么区别?
源代码文件包含程序员使用任何编程语言编写的代码
目标代码文件是编译后的机器语言代码
可执行文件是经过链接器将目标文件代码和开始文件代码、库文件代码合并成完整的机器语言代码生成的一个可执行程序
3.编程的7个主要步骤是什么?
(1)定义程序目标;(2)设计程序;(3)编写程序;(4)编译程序;(5)运行程序;(6)测试和调试程序:(7)维护和修改程序。
4.编译器的任务是什么?
将源码转换为机器语言代码(也叫目标文件代码)
5.链接器的任务是什么?
链接器将目标文件代码和开始文件代码、库代码合并成完整的机器语言代码生成一个可执行程序
第二章 C语言概述
一、简单的C程序
#include <stdio.h>
int main(void)
{
int num;
num = 1;
printf("I am a simple ");
printf("computer.\n");
printf("My favorite number is %d because it is first.\n",num);
return 0;
}
1.快速概要
这一节先简单介绍一下作用,后面会详细讨论
#include <stdio.h> 包含另一个文件
int main(void) 函数名
/* …*/ 注释
{ 函数体开始
int num 声明一个num变量
num = 1赋值表达式语句,把值1赋给名为num的变量
printf("I am a simple "); 调用一个函数
printf(“computer.\n”); 调用另一个函数,在上一条语句后面加上computer并换行,\n的作用是换行
printf(“My favorite number is %d because it is first.\n”,num); 这个printf函数是把num的值嵌套在双引号中和内容一起打印,%d告诉计算机以何种形式输出num的值
return 0; 可以先看作是结束main函数的作用
} 表示程序的结束
2.程序细节
(1)#include指令和头文件
#include <stdio.h>
#include这行代码是一条C预处理指令(preprocessor directive),什么是预处理?就是C编译器在编译之前会对源码进行一些准备工作,即预处理
stdio.h文件。这个包含许多供编译器使用的输入输出函数(printf())该文件。通常在C程序顶部的信息被称为头文件
为什么不内置输入输出函数在语言中,还要每次导入stdio.h文件?
原因之一是,并非所有的程序都会用到I/O(输入输出)包,轻装上阵是C语言的哲学
(2)main()函数
int main(void)
C程序一定从main()开始执行,除了main函数其他函数可以随便命名,main()
int是main()函数的返回值类型。这表明main()函数返回的值是整数,返回到操作系统
通常,函数后面的圆括号中包含一些传入函数的信息。这个例子没有传递任何信息。因此是单词void
没错上面的就算标准形式
不要这样写int main() ,void main()
(3)注释
/* 一个简单的C程序 */
注释可以卸载任何地方,在注释之间的会被编译器忽略
还有单行注释
//我是单行注释
C++,Java都是一样的方式,C++还没学过,Java的确是这样的哈哈哈
(4)花括号、函数体和块
{
? …
}
所有C函数都用花括号标记函数的开始和结束
(5)声明
int num;
在上面的例子中,声明完成了两件事,第一是在函数中有个名为num的变量,第二是int表名num是一个整数
int是关键字
num是标识符,也就是一个变量,函数或其他实体的名称。因此声明把特点标识符与计算机内存中的特点位置联系起来,同时确定了存储在某位置的信息类型或数据类型
C语言中所有的变量必须先声明才能使用。
int main(void)
{
int doors;
int dogs;
doors = 5;
dogs = 3;
return 0;
}
int main(void)
{
int doors;
doors = 5;
int dogs;
dogs = 3;
return 0;
}
(6)赋值
num = 1;
把值1赋值给num,不是num = 1,该表达式语句从右侧把值赋到左侧
(7)printf()函数
printf("I am a simple ");
printf("computer.\n");
printf("My favorite number is %d because it is first.\n",num);
圆括号表名printf是一个函数名。圆括号中的内容是参数,是实际参数,也就是确切的值
那么形式参数就是函数中用于存储值变量
这个函数可以将括号内的内容打印到屏幕上
(8)return语句
return 0;
可以理解为代码规范,在后面会i详细解释用途
3.程序规范
函数头和函数体
见名知意
使用空行,一条语句一行
写注释
4.多个函数
#include <stdio.h>
void buttler(void);
int main(void)
{
printf("I will summon the butler function.\n");
butler();
printf("Yes,Bring me some tea and writeable DVDs.\n");
return 0;
}
void butler(void)
{
printf("You rang,sir?\n");
}
该程序输入如下:
I will summon the butler function.
You rang,sir?
Yes,Bring me some tea and writeable DVDs.
其中butler()函数出现了3次。
第一次是函数原型,作用是告诉编译器要在程序中使用该函数;
第二次调用是函数调用的形式出现在main()中;
最后一次出现在函数定义中,函数定义就是函数本身的源代码
这是因为C的标准建议,要为所有程序中应用到的所有函数提供函数原型。标准include文件为标准库文件提供了函数原型
5.调试程序
(1)语法错误
编程和数学英语有亲密的联系,学习之余可以多学学英语和数学,提高英文阅读能力和逻辑思维能力
#include <stdio.h>
int main(void)
(
int n,int n2,int n3;
/*多行错误
n=5;
n2 = n * n;
n3 = n2 * n2;
return 0;
)
1、main()函数体用花括号
2、变量的声明应该这样写
int n , n2 ,n3;
int n;
int n2;
int n3;
3、注释有头有尾
(2)语义错误
n=5;
n2 = n * n;
n3 = n2 * n2;
程序出错就出现bug,解决bug叫调试程序
6.关键字和保留标识符
就是你不能在起这个名字了,这些词已经被计算机用了
7.小结
(1)C程序由一个或多个C函数组成。每个C程序必须包含一个main()函数,这是C程序要调用的第一个函数
(2)在C语言中,大部分语句都以分号结尾。
(3)声明为变量创建变量名和标识该变量中储存的数据类型。
(4)变量名是一种标识符。
(5)赋值表达式语句把值赋给变量,或者更一般地说,把值赋给存储空间。
(6)函数表达式语句用于调用指定的已命名函数。调用函数执行完毕后,程序会返回到函数调用后面的语句继续执行。
(7)关键字是C语言的词汇!!!
8.编程练习
纸上得来终觉浅,绝知此事要躬行。
1、
#include <stdio.h>
int main(void)
{
printf("Gustav Mahler\n");
printf("Gustav\n");
printf("Gustav\n");
printf("Gustav ");
printf("Mahler");
return 0;
}
结果:
Gustav Mahler Gustav Gustav Gustav Mahler
这一题还是挺简单的,掌握换行符\n就可以了
2、
#include <stdio.h>
int main(void)
{
printf("My name is pengyuyan.\n");
printf("My address is beijing.\n");
return 0;
}
My name is pengyuyan. My address is beijing.
3、
#include <stdio.h>
int main(void)
{
int age = 21;
int year = 365;
int days = age * year;
printf("Days are %d",days);
return 0;
}
Days are 7665
4、
#include <stdio.h>
void jolly(void);
void deny(void);
int main(void)
{
jolly();
jolly();
jolly();
deny();
return 0;
}
void jolly(void)
{
printf("For he's a jolly good fellow!\n");
return;
}
void deny(void)
{
printf("Which nobody can deny!\n");
return;
}
For he’s a jolly good fellow! For he’s a jolly good fellow! For he’s a jolly good fellow! Which nobody can deny!
5、
#include <stdio.h>
void br(void);
void ic(void);
int main(void)
{
br();
printf(", ");
ic();
printf("\n");
ic();
printf(",\n");
br();
return 0;
}
void br(void)
{
printf("Brazil, Russia");
return;
}
void ic(void)
{
printf("India, China");
return;
}
6、
#include <stdio.h>
int main(void)
{
int toes = 10;
printf("toes = %d\n", toes);
printf("toes * 2 = %d\n", toes * 2);
toes = toes * toes;
printf("toes ^ 2 = %d\n", toes);
return 0;
}
7、
#include <stdio.h>
void smile(void);
int main(void)
{
smile();
smile();
smile();
printf("\n");
smile();
smile();
printf("\n");
smile();
printf("\n");
return 0;
}
void smile(void)
{
printf("Smile!");
return;
}
8、
#include <stdio.h>
void one_three(void);
void two(void);
int main(void)
{
printf("Starting now:\n");
one_three();
printf("Done!\n");
return 0;
}
void one_three(void)
{
printf("one\n");
two();
printf("three\n");
return;
}
void two(void)
{
printf("two\n");
return;
}
第三章 数据和C
一、示例程序
#include <stdio.h>
int main(void)
{
float weight;
float value;
printf("Are you worth your weight in platinum\n");
printf("Let`s check it out.\n");
printf("Pleasee enter your weight in pounds:\n");
scanf("%f",&weight);
value = 1700.0 * weight * 14.55833;
printf("Your weight in platinum is worth $%.2f.\n",value);
printf("You are easily worth that! If platinum prices drop,\n");
printf ( "eat more to maintain your value. \n");
return 0;
}
结果为:
Are you worth your weight in platinum
Let`s check it out.
Pleasee enter your weight in pounds:
123
Your weight in platinum is worth $3044146.75.
You are easily worth that! If platinum prices drop,
eat more to maintain your value.
欧美日常使用的度量衡单位是常衡盎司( avoirdupois ounce ),而欧美黄金市场上使用的黄金交易计量单位是金衡盎司( troy ounce )。国际黄金市场上的报价,其单位“盎司”都指的是黄金盎司。常衡盎司属英制计量单位,做重量单位时也称为英两。相关换算参考如下:1常衡盎司=28.350克,1金衡盎司=31.104克,16常衡盎司=l磅。该程序的单位转换思路是:把磅换算成金衡盎司,即28.350÷31.104×16=14.5833。——译者注
1.程序细节
为了打印新类型的变量,在printf()中使用%f来处理浮点值。%.2中的.2用来精确控制,指定输出的浮点数只显示小数点后两位
%f说明scanf()要读取user键盘录入的浮点数,&weight告诉scanf()把输入的值赋给weight变量,scanf()使用&找到变量weight的地点。后面会详细说明&的作用
二、变量与常量数据
1.常量
有些数据类型,在程序运行前就已经定义好了,在运行过程中没有变化,这些称为常量
2.变量
其他数据类型在程序的运行过程中可能被改变和赋值,这些称为变量
三、数据类型关键字
位、字节、字和字长
弄了好久都没分清,看了这书后,我可以了
当然不用清除到底,就像刚学开车不需要掌握汽车的原理一样
首先,位、字节、字都是计算机数据单元或存储单元的术语
位是计算机存储的最小单位要么是0或1
字节是计算机常用的存储单位,1个字节(Byte)等于8位(bit)
计算机每个字所包含的位数称为字长,指计算机一次能处理的二进制数字的数目,字长越大计算机处理的越快
字(word)是计算机的自然存储单位,对于8位的计算机1个字长只有8位
四.C语言基本数据类型
1.int类型
也就是数字类型,整型,int类型必须是整数
声明为变量创建和标记存储空间,并指定初始值
2.其他整数类型
short int类型 占用的存储空间可能比int少,常用于数值较小的场合节省空间
long int 适用于数值较大的场合
long long 占用存储空间比long多,适用于更大的场合
unsigned int或unsigned用于非负值的场合
signed 强调使用由符号类型的意图
实例:
#include <stdio.h>
int main(void)
{
long int estine;
long johns;
short int erns;
short ribs;
unsigned int s_count;
unsigned players;
long long age;
return 0;
}
int类型那么多,应该如何选择﹖首先,考虑unsigned类型。这种类型的数常用于计数,因为计数不用负数。而且,unsigned类型可以表示更大的正数。
long常量和long long常量
通常,程序代码中使用的数字(如,2345)都被储存为int类型。如果使用1000000这样的大数字,超出了int类型能表示的范围,编译器会将其视为long int类型(假设这种类型可以表示该数字)。如
整数溢出
如果整数超出了相应类型的取值范围会怎样?
这种情况称为整数溢出
3.使用字符:char类型
char用来存字符(如,字母或标点符号)
char类型用于储存字符(如,字母或标点符号),但是从技术层面看,char是整数类型。因为char类型实际上储存的是整数而不是字符。计算机使用数字编码来处理字符,即用特定的整数表示特定的字符。
3.1 ASCII编码?
现实生活中的数据在计算机中怎么表示
计算机所有数据和运算时都要使用二进制表示
ASCII编码是个规则,按照这个规则将生活中的信息用二进制表示出来
3.2 转义字符
4._Bool类型
用来表示布尔值,即逻辑值true和false
5.float、double和long double
flaot和double用来表示小数,double比float更精确
5.1浮点值的上溢和
上溢就是超出了当前类型能表达的范围,上溢时,不能再继续运算,一般要进行中断处理。
下溢就是小于最小取值范围,称为下溢。 下溢时,一般把浮点数各位强迫为零,机器仍可继续运算。
五、关键概念
C语言提供了大量的数值类型,目的是为程序员提供方便。那以整数类型为例,C认为一种整型不够,提供了有符号、无符号,以及大小不同的整型,以满足不同程序的需求。
计算机在内存中用数值编码来表示字符。最常用的是ASCII编码
基本数据类型分为两大类:整数型和浮点型
Java是基本数据类型和引用数据类型
六、编程练习
C Primer Plus 第六版(中文版)第三章(完美修订版)编程练习答案_CLOVER的博客-CSDN博客
第四章 字符串和格式化输入输出
一、字符串简介
字符串是一个或多个字符的序列
双引号仅告知编译器它括起来的是字符串,单引号用于标识
单个字符
1.1 char类型数组和null字符
C语言没有专门用于储存字符串的变量类型,字符串都被储存在char类型的数组中。数组由连续的存储单元组成,字符串中的字符被储存在相邻的存储单元中,每个单元储存一个字符
1.2 什么是数组
可以把数组看作是一行连续的多个存储单元
数组是同类型数据元素的有序序列
char name[40]
name后面的方括号表民这是一个数组,方括号后面的40表明该数组中的元素数量
1.3 字符和字符串
字符串常量"x"和字符常量’x’不同。区别之一在于**’ x '是基本类型(char),而"x"是派生类型(char数组);区别之二是"x"实际上由两个字符组成: 'x’和空字符\0**
1.4 strlen()和sizeof()区别
上一章提到了sizeof运算符,它以字节为单位给出对象的大小。strlen ()函数给出字符串中的字符长度
#include <stdio.h>
#include <string.h>
#define PRAISE "Hello World!"
int main(void)
{
char name[40];
printf("Name:");
scanf("%s",name);
printf("%zd %zd",strlen(name),sizeof(name));
return 0;
}
结果为:
Name:pyy
3 40
PS D:\Code\C>
sizeof运算符报告,name数组有40个存储单元。但是,只有前11个单元用来储存Serendipi所以strlen ()得出的结果是1l。name数组的第12个单元储存空字符,strlen()并未将其计入
二、常量和C预处理器
有时,在程序中要使用常量。例如,可以这样计算圆的周长:circumference = 3.14159 * diameter;
这里3.1415926代表常量pi(Π)
这种情况最好用符号常量,如下计算机会自动进行替换
circumference = pi * diameter;
常量比数字表达的信息更多
owed = 0.015 * housevalue;
owed = taxrate * housevalue; 如果阅读一个很长的程序,第2条语句所表达的含义更清楚。
如何创建符号常量?
float taxrate;
taxrate = 0.015;
这样做提供了一个符号名,但是taxrate是一个变量,程序可能会无意间改变它的值。
C语言还提供了一种预处理器的方式,只需在顶部添加一行
#define TAXRATE 0.015
编译程序时,程序中所有的TA.XRATE都会被替换成0.015。这一过程被称为编译时替换(compile-timesubstitution)。在运行程序时,程序中所有的替换均已完成
2.1 const限定符
C90标准新增了const关键字,**用于限定一个变量为只读。**其声明如下:const int MONTHS = 12; ll MONTHS在程序中不可更改,值为12
这使得MONTHS 成为一个只读值。也就是说,可以在计算中使用MONTHS,可以打印 MONTHs,但是不能更改MONTHs的值。const用起来比#define更灵活
const修饰的是变量,为只读
三、printf()和scanf ()
虽然printf ()是输出函数,scanf()是输入函数。工作原理几乎一致
3.1 printf()
请求printf()函数打印数据的指令要与待打印数据的类型相匹配。例如,打印整数时使用%d,打印字符时使用%c。这些符号被称为转换说明(conversion specification),它们指定了如何把数据转换成可显示
转换说明及打印的输出结果
格式字符串中的转换说明一定要与后面的每个项相匹配!
3.1.1 printf ()的转换说明修饰符
在%和转换字符之间插入修饰符可修饰基本的转换说明
常见的:
.数字:表示的就是精度
5.2f意思是字段宽度为5,小数点后两位数字
数字:代表的是字段宽度如%4d
3.2 scanf ()
如果用scanf ()读取基本变量类型的值,在变量名前加上一个&;
如果用scanf()把字符串读入字符数组中,不要使用&。
3.2.1 scanf ()的转换说明修饰符
简单了解一下…
这本书也太tm难学了!!!
四、关键概念
字符串是一系列被视为一个处理单元的字符。
char name [ 30]; 要确保有足够多的元素来储存整个字符串(包括空字符)
strlen()函数(声明在string.h头文件中)可用于获得字符串的长度(末尾的空字符不计算在内)。scanf ()函数中的转换说明是%s时,可读取一个单词。
C预处理器为预处理器指令(以#符号开始)查找源代码程序,并在开始编译程序之前处理它们。
printf()和scanf ()函数对输入和输出提供多种支持。两个函数都使用格式字符串,其中包含的转换说明表明待读取或待打印数据项的数量和类型。另外,可以使用转换说明控制输出的外观:字段宽度、小数位和字段内的布局。
五、编程练习
代码和结果都放在代码块中了!
1.c
#include <stdio.h>
int main(void)
{
char fname[20], lname[20];
printf("Please enter your first name: ");
scanf("%19s", fname);
printf("Please enter your last name: ");
scanf("%19s", lname);
printf("Hello! %s, %s.\n", fname, lname);
return 0;
}
2.c
#include <stdio.h>
#include <string.h>
int main(void)
{
int len = 0;
char name[20];
printf("Please enter your name:");
scanf("%19s", &name);
len = strlen(name);
printf("Print your name:\n");
printf("a.\"%s\"\n", name);
printf("b.\"%20s\"\n", name);
printf("c.\"%-20s\"\n", name);
printf("d.%*s\n", len + 3, name);
return 0;
}
Please enter your name:pyy
Print your name:
a."pyy"
b." pyy"
c."pyy "
d. pyy
3.c
#include <stdio.h>
int main(void)
{
float num;
printf("Please enter a float number:");
scanf("%f", &num);
printf("The input is %.1f or %.1e.\n", num, num);
return 0;
}
Please enter a float number:2.3
The input is 2.3 or 2.3e+000.
这是C语言的浮点数常量的科计数法
2.3e+02
2.3*10的二次方
1.0e+003
1.0*10的三次方
4.c
#include <stdio.h>
#define LEN 30
int main(void)
{
float heigh;
char name[LEN];
printf("Please enter your name:");
scanf("%29s", &name);
printf("Hello! %s, how tall you are(inch):", name);
scanf("%f", &heigh);
printf("%s, you are %.3f feet tall.\n", name, heigh / 12.0);
return 0;
}
Please enter your name:pyy
Hello! pyy, how tall you are(inch):178
pyy, you are 14.833 feet tall.
5.c
#include <stdio.h>
#define BIT 8
int main(void)
{
float speed, size, time;
printf("Please enter net speed(Mbit/s):");
scanf("%f", &speed);
printf("Please enter file size(MB):");
scanf("%f", &size);
time = size * BIT / speed;
printf("At %.2f megabits per secnod, ", speed);
printf("a file of %.2f megabytes ", size);
printf("downloads in %.2f seconds.\n", time);
return 0;
}
简单不作详细解释
Please enter net speed(Mbit/s):10
Please enter file size(MB):20
At 10.00 megabits per secnod, a file of 20.00 megabytes downloads in 16.00 seconds.
6.c
#include <stdio.h>
#include <string.h>
int main(void)
{
int x, y;
char fname[20], lname[20];
printf("Please enter your first name: ");
scanf("%19s", &fname);
printf("Please enter your last name: ");
scanf("%19s", &lname);
x = strlen(fname);
y = strlen(lname);
printf("%s %s\n", fname, lname);
printf("%*d %*d\n", x, x, y, y);
printf("%s %s\n", fname, lname);
printf("%-*d %-*d\n", x, x, y, y);
return 0;
}
Please enter your first name: pyy
Please enter your last name: caq
pyy caq
3 3
pyy caq
3 3
7.c
#include <stdio.h>
#include <float.h>
int main(void)
{
float f_value = 1.0 / 3.0;
double d_value = 1.0 / 3.0;
printf("1.0 / 3.0 display 6 decimal places:\n");
printf("f_value = %.6f\nd_value = %.6lf\n", f_value, d_value);
printf("\n1.0 / 3.0 display 12 decimal places:\n");
printf("f_value = %.12f\nd_value = %.12lf\n", f_value, d_value);
printf("\n1.0 / 3.0 display 16 decimal places:\n");
printf("f_value = %.16f\nd_value = %.16lf\n", f_value, d_value);
printf("\nfloat and double maximum significant digits:\n");
printf("FLT_DIG = %d, DBL_DIG = %d\n", FLT_DIG, DBL_DIG);
return 0;
}
1.0 / 3.0 display 6 decimal places:
f_value = 0.333333
d_value = 0.333333
1.0 / 3.0 display 12 decimal places:
f_value = 0.333333343267
d_value = 0.333333333333
1.0 / 3.0 display 16 decimal places:
f_value = 0.3333333432674408
d_value = 0.3333333333333333
float and double maximum significant digits:
FLT_DIG = 6, DBL_DIG = 15
第五章 循环
循环简介
组织程序是处理数据的另一个方面,让程序按正确的顺序执行各个步骤。C有许多语言特性,帮助你完成组织程序的任务。循环就是其中一个特性,循环能重复执行行为,让程序更有趣、更强大。
循环的分类
既然循环结构在程序中大量存在,所以为了功能的实现,程序中主要有一下四种循环语句或者结构存在。
- while 语句;
- do … while 语句;
- for 语句;
- 嵌套循环结构。
注意事项
不要让程序进入死循环,不能结束的循环会让你的程序在耗尽系统为它提供的计算资源后崩溃的。
真值问题
在C语言中,一直用int类型的变量表示真/假值。
C99专门针对这种类型的变量新增了_Bool类型该类型是以英国数学家George Boole的名字命名的,他开发了用代数表示逻辑和解决逻辑问题。_
_在编程中表示真或假的变量被称为布尔变量(Boolean variable),所以_Bool是C语言中布尔变量的类型名。
Boo类型的变量只能储存1(真)或(假) 如果把其他非零数值赋给Bool类型的变量,该变量会被设置为1。这反映了C把所有的非零值都视为真。
一、while循环
(1)循环的语法
while( 循环条件 )
{
}
(2)循环的执行过程
(3) While 循环的使用场景
? 在程序中,需要将特定语句部分在满足循环条件的情况下循环执行的时候使用这个语句。这个循环在很多情况下就如同我们在完成自己的作业。我们每天的作业数量是不同的,没有办法进行设定每天定量要写多少。
? 但是,我们知道一条准则,就是如果没有写完,那就要一直写下去,直到写完为止。这里的循环判断条件就是作业没有写完.那么这个就是一个 while 循环。每次都会检查一个条件,如果条件满足,那么就一直循环下去。
(4)循环的使用实例
#include <stdio.h>
int main()
{
int x = 10;
while(x>0)
{
printf("Number: %d\n",x);
x--;
}
return 0;
}
? ? ? Number: 10 ? Number: 9 ? Number: 8 ? Number: 7 ? Number: 6 ? Number: 5 ? Number: 4 ? Number: 3 ? Number: 2 ? Number: 1
(5)总结while
? while语句是先进行条件判断,然后再决定是不是要执行被括号包围的循环体中的内容是不是要被执行。
? 如果循环条件满足则执行。执行程序循环体中的内容。如果不满足则不执行循环。这也就是说,如果在第一次判断循环条件是否满足的时候,如果判断结果是不满足,那么包括在循环语句中的内容就一次也不会被执行,直接会被忽略。
Tips:这个语句有时候会有一个特别的用途,就是在写单片机程序的时候,你有时候需要采用轮询的方式来采集端口的信息,也就是需要不断的扫描每个端口的状态。这个时候,程序会使用 while(1) 来进行。这个语句其实是一个不会停止的循环。程序会反复不断的来执行程序循环体中的内容。
二、for循环
(1)for 循环的语法
for(控制循环的变量; 循环判断条件; 循环变量增减变化)
{
}
(2)for 循环的使用场景
当我们可以确定循环的控制条件的时候采用这个语句。这里的循环一般都是有限次的循环。我们都知道高斯小时候计算 1 到 100 累加的故事。那么 for 循环就可以用来解决这种头尾数字都固定的反复一致的任务。这里就是从数字 1 一直相加到数字 100 。这就是 for 循环的一个应用。
for语句使用3个表达式控制循环过程,分别用分号隔开。initialize表达式在执行for语句之前只执行一次;然后对test表达式求值,如果表达式为真(或非零),执行循环一次;接着对update表达式求值,并再次检查test表达式。for语句是一种入口条件循环,即在执行循环之前就决定了是否执行循环。因此,for循环可能一次都不执行。statement部分可以是一条简单语句或复合语句。
形式:for(initialize; test; update){
statement;
}
在test为假或0前,重复执行statement部分
实例:
for(n = 0;n < 10; n++){
printf("%d %d \n",n,n*2+1);
}
(3)for的实例
#include <stdio.h>
int main()
{
for (int i = 0; i < 10; i++)
{
printf("No. %d: Hello C Language!\n", i);
}
return 0;
}
No. 0: Hello C Language!
No. 1: Hello C Language!
No. 2: Hello C Language!
No. 3: Hello C Language!
No. 4: Hello C Language!
No. 5: Hello C Language!
No. 6: Hello C Language!
No. 7: Hello C Language!
No. 8: Hello C Language!
No. 9: Hello C Language!
三、do-While
(1)概述
while循环和for循环都是入口条件循环,即在循环的每次迭代之前检查测试条件
C语言还有出口条件循环(exit-condition loop),即在循环的每次迭代之后检查测试条件,这保证了至少执行循环体中的内容一次。这种循环被称为do while循环。
(2) do-while 循环的使用场景
当需要先执行一次循环体内部的语句,然后再进行是否再次执行循环语句的时候使用。这有点像你吃饭,先尝一下食物是不是好吃,然后再决定是不是要继续吃下去。
(3) 通用形式
do
? statement
while (expression);
do while循环在执行完循环体后才执行测试条件,所以至少执行循环体一次;
而for循环或while循环都是在执行循环体之前先执行测试条件。
形式:
do
? statement;
while();
实例:
do
? scanf("%d ",&num);
while(num !=20);
四、嵌套循环
可以想象俄罗斯套娃,循环套循环
(1)乘法口诀表
#include <stdio.h>
int main(void)
{
for (int i = 1; i < 10; i++)
{
for (int j = 1; j < i+1; j++)
{
int sum = i * j;
printf("%d * %d = %d ",i,j,sum);
}
printf("\n");
}
return 0;
}
1 * 1 = 1
2 * 1 = 2 2 * 2 = 4
3 * 1 = 3 3 * 2 = 6 3 * 3 = 9
4 * 1 = 4 4 * 2 = 8 4 * 3 = 12 4 * 4 = 16
5 * 1 = 5 5 * 2 = 10 5 * 3 = 15 5 * 4 = 20 5 * 5 = 25
6 * 1 = 6 6 * 2 = 12 6 * 3 = 18 6 * 4 = 24 6 * 5 = 30 6 * 6 = 36
7 * 1 = 7 7 * 2 = 14 7 * 3 = 21 7 * 4 = 28 7 * 5 = 35 7 * 6 = 42 7 * 7 = 49
8 * 1 = 8 8 * 2 = 16 8 * 3 = 24 8 * 4 = 32 8 * 5 = 40 8 * 6 = 48 8 * 7 = 56 8 * 8 = 64
9 * 1 = 9 9 * 2 = 18 9 * 3 = 27 9 * 4 = 36 9 * 5 = 45 9 * 6 = 54 9 * 7 = 63 9 * 8 = 72 9 * 9 = 81
五、关键概念
循环是一个很强大的工具,只能多用,多锻炼自己的编程思维
不需要死记硬背
测试条件,结果为0遍试假,非0表示真
六、编程练习
1.c
#include <stdio.h>
#define LEN 26
int main(void)
{
int n;
char letters[LEN];
for (n = 0; n < LEN; n++)
{
letters[n] = 'a' + n;
}
printf("Here are %d letters:\n", LEN);
for (n = 0; n < LEN; n++)
{
printf("%-3c", letters[n]);
}
return 0;
}
Here are 26 letters:
a b c d e f g h i j k l m n o p q r s t u v w x y z
2.c
#include <stdio.h>
#define N 5
int main(void)
{
int i, j;
for (i = 1; i <= N; i++)
{
for (j = 1; j <= i; j++)
{
printf("$");
}
printf("\n");
}
return 0;
}
这就是乘法口诀的样式啊
3.c
#include <stdio.h>
#define N 6
int main(void)
{
int i, j;
for (i = 1; i <= N; i++)
{
for (j = 0; j < i; j++)
{
printf("%c", 'F' - j);
}
printf("\n");
}
return 0;
}
F
FE
FED
FEDC
FEDCB
FEDCBA
4.c
#include <stdio.h>
#define N 6
int main(void)
{
int i, j;
char ch = 'A';
for (i = 1; i <= N; i++)
{
for (j = 1; j <= i; j++)
{
printf("%c", ch++);
}
printf("\n");
}
return 0;
}
5.c
#include <stdio.h>
int main(void)
{
int i, j;
char ch;
printf("Please enter a upper letter: ");
scanf("%c", &ch);
int length = ch - 'A';
printf("The pyramid of %c is:\n", ch);
for (i = 0; i <= length; i++)
{
char t = 'A' - 1;
for (j = 0; j < length - i; j++)
{
printf(" ");
}
for (j = 0; j <= i; j++)
{
printf("%c", ++t);
}
for (j = 0; j < i; j++)
{
printf("%c", --t);
}
printf("\n");
}
return 0;
}
6.c
#include <stdio.h>
int main(void)
{
int i, upper, lower;
printf("Please input the upper limits: ");
scanf("%d", &upper);
printf("Please input the lower limits: ");
scanf("%d", &lower);
printf("%-10s%-10s%-10s\n", "number", "square", "cube");
for (i = lower; i <= upper; i++)
{
printf("%-10d%-10d%-10d\n", i, i * i, i * i * i);
}
printf("Done.\n");
return 0;
}
7.c
#include <stdio.h>
#include <string.h>
#define LEN 20
int main(void)
{
int i;
char str[LEN];
printf("Please enter a word: ");
scanf("%19s", str);
printf("The word is:\n");
printf("%s\n", str);
printf("Reversing the word is:\n");
for (i = strlen(str) - 1; i >= 0; i--)
{
printf("%c", str[i]);
}
return 0;
}
8.c
#include <stdio.h>
int main(void)
{
double i, j;
printf("Please enter two numbers (q to quit): ");
while (scanf("%lf %lf", &i, &j) == 2)
{
printf("(%g - %g) / (%g * %g)", i, j, i, j);
printf(" = %g\n", (i - j) / (i * j));
printf("You can enter again (q to quit): ");
}
printf("Done.\n");
return 0;
}
9.c
#include <stdio.h>
double cal(double n, double k);
int main(void)
{
double i, j;
printf("Please enter two numbers (q to quit): ");
while (scanf("%lf %lf", &i, &j) == 2)
{
printf("(%g - %g) / (%g * %g)", i, j, i, j);
printf(" = %g\n", cal(i, j));
printf("You can enter again (q to quit): ");
}
printf("Done.\n");
return 0;
}
double cal(double n, double k)
{
return (n - k) / (n * k);
}
10.c
#include <stdio.h>
int main(void)
{
int upp, low, i;
printf("Enter lower and upper integer limits: ");
while ((scanf("%d %d", &low, &upp) == 2) && (upp > low))
{
int sum = 0;
for (i = low; i <= upp; i++)
{
sum += i * i;
}
printf("The sums of the squares ");
printf("from %d to %d is %d\n", low * low, upp * upp, sum);
printf("Enter next set of limits: ");
}
printf("Done\n");
return 0;
}
11.c
#include <stdio.h>
#define N 8
int main(void)
{
int i, a[N];
printf("Please enter 8 numbers:\n", N);
for (i = 0; i < N; i++)
{
scanf("%d", &a[i]);
}
printf("Reverse order printing 8 numbers:\n", N);
for (i = N - 1; i >= 0; i--)
{
printf("%-3d", a[i]);
}
return 0;
}
12.c
#include <stdio.h>
int main(void)
{
int i, n;
printf("Please enter a number (<= 0 to quit): ");
while ((scanf("%d", &n) == 1) && (n > 0))
{
double res1 = 0.0;
double res2 = 0.0;
for (i = 1; i <= n; i++)
{
res1 += 1.0 / i;
if (i % 2 == 1)
{
res2 += 1.0 / i;
}
else
{
res2 -= 1.0 / i;
}
}
printf("1.0 + 1.0/2.0 + 1.0/3.0 + 1.0/4.0 + ...");
printf("sum are %g\n", n, res1);
printf("1.0 - 1.0/2.0 + 1.0/3.0 - 1.0/4.0 + ...");
printf("sum are %g\n", n, res2);
printf("The sum of the first %d items of the two sequences is %g\n", n, res1 + res2);
printf("\nYou can enter again (<= 0 to quit): ");
}
printf("Done.\n");
return 0;
}
13.c
#include <stdio.h>
#define N 8
int main(void)
{
int a[N], i;
int val = 2;
for (i = 0; i < N; i++)
{
a[i] = val;
val *= 2;
}
i = 0;
printf("Here are the results for array:\n", N);
do
{
printf("%d ", a[i++]);
} while (i < N);
printf("\nDone.\n");
return 0;
}
14.c
#include <stdio.h>
#define N 8
int main(void)
{
int i;
double a[N], b[N];
printf("Please enter %d numbers:\n", N);
for (i = 0; i < N; i++)
{
scanf("%lf", &a[i]);
}
b[0] = a[0];
for (i = 1; i < N; i++)
{
b[i] = a[i] + b[i - 1];
}
printf("Here are the results for array a:\n");
for (i = 0; i < N; i++)
{
printf("%-3g", a[i]);
}
printf("\nHere are the results for array b:\n");
for (i = 0; i < N; i++)
{
printf("%-3g", b[i]);
}
printf("\nDone.\n");
return 0;
}
15.c
#include <stdio.h>
#define LEN 255
int main(void)
{
int i = 0;
char input[LEN];
printf("Please enter a string:\n");
do
{
scanf("%c", &input[i]);
} while (input[i] != '\n' && ++i && i < LEN);
printf("Reversing print the string is:\n");
for (i--; i >= 0; i--)
{
printf("%c", input[i]);
}
printf("\nDone.\n");
return 0;
}
16.c
#include <stdio.h>
#define RATE_SIMP 0.10
#define RATE_COMP 0.05
#define INIT_AMT 100.0
int main(void)
{
int years = 0;
double daphne = INIT_AMT;
double deirdre = INIT_AMT;
do
{
daphne += RATE_SIMP * INIT_AMT;
deirdre += RATE_COMP * deirdre;
years++;
} while (deirdre < daphne);
printf("Investment values after %d years:\n", years);
printf("Daphne: $%.2f\n", daphne);
printf("Deirdre: $%.2f\n", deirdre);
printf("Deirdre(invest) > Daphne(invest)\n");
return 0;
}
17.c
#include <stdio.h>
#define TAX 0.08
int main(void)
{
int i = 0;
double Chuckie = 100.0;
do
{
i++;
Chuckie += Chuckie * TAX;
Chuckie -= 10;
printf("(%d)account:%g.\n", i, Chuckie);
} while (Chuckie > 9);
printf("After %d years:\n", ++i);
printf("Chuckie has taken all of the money!\n");
return 0;
}
18.c
#include <stdio.h>
int main(void)
{
int i = 1;
int friends = 5;
while (friends < 150)
{
printf("At %d weeks, Rabnud has", i);
printf("%4d friends.\n", friends);
friends = 2 * (friends - i++);
}
printf("At %d weeks, over Dunbar's number(150).\n", i);
return 0;
}
第七章 指针
指针
它来了,它来了。C语言的灵魂!
没错它就是指针
上干货!!!
一、什么是指针
从根本上看,指针是一个值为内存地址的变量,如int类型的值是整数
char类型的值是字符
指针变量的值就是内存地址
二、 指针的用法
把指针作为函数参数使用,以及为何这样用
假设一个指针变量名是ptr,可以编写如下语句:
ptr = &pooh; //把pooh的地址赋给ptr
对于这条语句,我们说ptr“指向”pooh。
ptr和&pooh 的区别是ptr是变量,而&pooh是常量。或者,ptr是可修改的左值,而&pooh是右值。
当然还可以把ptr指向别处: ptr = &bah; //把ptr指向bah,而不是pooh 现在ptr的值是bah的地址。 要创建指针变量,先要声明指针变量的类型。假设想把ptr声明为储存int类型变量地址的指针,就要使用下面的新运算符。
2.1 间接运算符
假设已知 ptr指向bah,
如下所示:
ptr = &bah; 然后使用间接运算符* (indirection operator)找出储存在 bah 中的值,该运算符有时也称为解引用运算符(dereferencing operator)。不要把间接运算符和二元乘法运算符(*)混淆,虽然它们使用的符号相同,但语法功能不同。
val = *ptr;//找出ptr指向的值
语句ptr = &bah;和val = *ptr;放在一起相当于下面的语句;
val = bah
我的理解:
指针变量里面存放的是内存地址,既然是存放,那就有对于的取出操作,怎么取出?就在指针变量前面加上*即可!
小总结:
地址运算符:&
后面跟一个变量名时,&给出该变量的地址
示例:
&nurse表示变量nurse的地址
地址运算符:*
后跟一个指针名或地址时,*给出存储在指针指向地址上的值
示例:
nurse = 22;
ptr = &nurse; //指向nurse的指针
val = *ptr; //ptr指向的地址上的值赋给val
以上三条语句的结果是把22赋给val
2.2 声明指针
声明指针变量时,必须指定指针所指向变量的类型。咋听着这么绕呢?
用我的理解来说就是:
指针的变量类型要和指针所指向变量的类型一样,指针值的变量是啥类型,指针变量就是啥类型
例如:
? int * pi; // pi是指向int类型变量的指针
? char * pc; // pc是指向char类型变量的指针
? float * pf, * pg; // pf、pg都是指向float类型变量的指针
类型说明符表明了指针所指向对象的类型,星号(*)表明声明的变量是一个指针。int * pi;声明的意思是pi是一个指针,*pi是int类型
这个图是从上往下看,能简单理解下使用指针的过程
*和指针名之间的空格可有可无。通常,程序员在声明时使用空格,在解引用变量时省略空格。
2.3 使用指针在函数间通信
#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;
*u = *v;
*v = temp;
}
程序分析
首先看函数调用,
interchange(&x,&y);这里的两个参数,不是x和y的值,而是x和y的地址
后来就是通过一个temp变量进行变量的地址交换
小总结:
变量:名称、地址和值
编写程序时,可以认为变量有两个属性:名称和值(还有其他性质,如类型,暂不讨论)。
计算机编译和加载程序后,认为变量也有两个属性:地址和值。地址就是变量在计算机内部的名称。
简而言之,普通变量把值作为基本量,把地址作为通过&运算符获得的派生量,而指针变量把地址作为基本量,把值作为通过*运算符获得的派生量。
三、指针和数组
#include <stdio.h>
#define SIZE 4
int main(void)
{
short dates[SIZE];
short * pti;
short index;
double bills[SIZE];
double * ptf;
pti = dates;
ptf = bills;
for (index = 0;index < SIZE; index++)
{
printf("pointers+%d : %p %p\n",index,pti + index,ptf+index);
}
return 0;
}
pointers+0 : 000000000061FE00 000000000061FDE0
pointers+1 : 000000000061FE02 000000000061FDE8
pointers+2 : 000000000061FE04 000000000061FDF0
pointers+3 : 000000000061FE06 000000000061FDF8
我们的系统中,地址按字节编址,short类型占用2字节,double类型占用8字节。在C中,指针加1指的是增加一个存储单元。对数组而言,这意味着把加1后的地址是下一个元素的地址,而不是下一个字节的地址,这是为什么必须声明指针所指向对象类型的原因之一。只知道地址不够,因为计算机要知道储存对象需要多少字节(即使指针指向的是标量变量,也要知道变量的类型,否则*pt就无法正确地取回地址上的值)。
未完待续…
算是完成了国庆的一个自我检测
|