Mr. Kin's Blog

计算机知识分享/软件应用讲解

第一章:Web语言:认识HTML

章节总结(详见书籍P36)

  • HTML和CSS是用来创建网页的语言。
  • Web服务器存储并提供由HTML和CSS创建的网页。浏览器获取页面,并根据HTML和CSS显示网页的内容。
  • HTML是超文本标记语言(HyperText Markup Language)的缩写,用来建立网页的结构。
  • CSS是层叠样式表(Cascading Style Sheets)的缩写,用来控制HTML的表现。
  • 通过HTML,利用标记来标示内容提供结构。把匹配标记以及它们包围的内容称为元素。
  • 元素由3部分组成:一个开始标记、内容和一个结束标记。不过有些元素(比如<img>)有所例外。
  • 开始标记可以有属性。比如本章出现的一个属性:type。
  • 结束标记在左尖括号后面、标记名前面有一个“/”,以明确这是结束标记。
  • 所有页面都要有一个<html>元素,其中要有一个<head>元素和一个<body>元素。
  • 网页的信息放在<head>元素里。
  • <body>元素里的内容是用户在浏览器里看到的东西。
  • 大多数空白符(制表符、回车、空格)都会被浏览器忽略,不过可以利用空白符让HTML更有可读性。
  • 可以在<style>元素中写CSS规则,为HTML网页增加CSS。<style>元素总要放在<head>元素里。
  • 可以使用CSS在HTML中指定元素的特性.

本章节练习文件

请注意:本教程适用平台为Windows OS。

1   什么是运行库

2   安装软件或运行软件时提示dll缺失等现象产生的原因

使用不同框架环境来开发的程序需要相对应的运行库才能正常工作,例如VC的程序需要VC运行库,VB的程序需要VB运行库,java程序需要Java Runtime一样,而使用 .Net 开发的程序需要在 .NET Framework下才能运行。

而纯净的windows系统是不自带有以上这些库或者内置一个版本的库。比如windows系统不自带VC库和java runtime;win10自带的.net框架一般为4.7(老版本的win10可能为4.6或者更早);win10自带的dx则为dx12。当系统无法提供程序所需的库时,例如没有该库,或者内置库与程序所需的版本不一致,又或者相应库文件已损坏,那么便会弹出dll缺失等运行库问题的错误提示窗口。

3   解决方法

请根据错误提示窗口的信息找对应的工具,「.dll缺失」一般排查DX或者VC库即可,「.net framework缺失」一般排查NET框架即可。

4   DX库和VC库修复:

注:请注意要下载增强版,增强版才含有VC库(上述链接便是增强版的)。

DX修复工具修复VC失败的调试信息查看:

  1. 工具->选项->常规->(勾选)修复失败时启用调试信息
  2. 执行「检测并修复」
  3. 点击修复失败的项目(软件中会显示蓝色链接),如果有显示未修复文件的具体明细,右击文件选择「在线修复」。如果没有文件明细,只有针对某个C++具体版本的错误描述,右击选择「更多提示」,看完提示后再次右击项目,有可能出现「切换至详细列表」,这时候使用「在线修复」即可解决。

4.1   vc库无限报错弹窗

安装和卸载vc2017库出现弹窗,标题为Microsoft Visual C++ 2017 x64 Minimum Runtime - 14.10.25008,内容提示为 vc_runtimeAdditional_x64.msi is not a valid installation package for product Microsoft Visual C++ 2017 x64 Minimum Runtime - 14.10.25008。

解决方式:使用官方的故障排除程序(troubleshooter)先卸载掉已存在的残留安装信息,然后重新安装vc库。

4.2   vc库安装提示「请确认C:\ProgramData\Package Cache文件夹存在并且有访问权限」

故障现象:安装vc2015-2022库失败,dx修复工具提示「请确认C:\ProgramData\Package Cache文件夹存在并且有访问权限」

解决方法:

  1. 先执行常规的卸载,然后使用官方的故障排除程序(troubleshooter)先卸载掉已存在的残留安装信息。
  2. 强制删除C:\ProgramData\Package Cache路径下的所有文件。
  3. 下载最新的vc库安装包安装,一般先装好x86,再装x64。

5   .NET框架

注:请自己选择需要的版本下载并进行安装。建议安装或修复运行库后请重启系统。关于版本选择,请看以下说明!!!

注意!!!.Net Framework版本关系:
.Net版本并非完全独立,但也不支持向下兼容。目前为止微软推出了3个版本的CLR,分别是 1.1、2.0 、4.0。 .Net 4是基于CLR4的,而.Net 2.0 3.0 3.5都是基于 CLR2.0, 3.0 3.5其实只是在2.0的基础上增加了新的功能,并没有改变CLR。
换而言之,你的程序需要2.0/3.0/3.5之中的任意一个版本时,安装.Net 3.5 SP1就可以了。
所以,如果只是想扩展系统的运行库的话,以win10 OS为例,那么只需要选择安装.Net 3.5 SP1和.Net 4.8(最新的.Net 4.X的就行,4.8是我当初写该教程时最新的版本)

5.0.1   Win10 .Net Framework 3.5 安装错误 0x800f0950 / 0x800F0954

问题:一般是系统更新程序WUserver无法争取获取更新文件,可能是由于精简或者相关服务项被禁用导致引起。

解决方法:

  1. 使用离线方式安装(推荐此法)
  2. 恢复WUserver的正常运行,确保在线安装的功能可以正常获取更新文件

离线方式安装步骤:

  1. 下载当前系统版本所对应的系统镜像
  2. 把source文件夹中的sxs文件夹解压出来,例如C:\path\sxs
  3. 管理员身份打开powershell,运行安装命令:dism.exe /online /enable-feature /featurename:NetFX3 /Source:C:\path\sxs

6   参考文献

[1] The Visual C++ missing error PLAGUE! Here’s how to fix that pesky missing .MSI file in 5 easy steps![EB/OL]. https://www.youtube.com/watch?v=ybr5ExVOlqI.
[2] 安装.NET Framework 3.5 Error 0x800f0950 in Windows 10[EB/OL]. https://blog.csdn.net/sinat_29315697/article/details/90438542.
[3] Win10 .Net Framework 3.5 安装错误 0x800F0954[EB/OL]. https://blog.csdn.net/u012722571/article/details/106336899.
[4] DirectX修复工具使用技巧之二——手动修复C++创建失败的文件[EB/OL]. https://blog.csdn.net/VBcom/article/details/114080642.

第三章:字符串、向量和数组

练习3.1

使用恰当的using声明重做1.4.1节(第11页)和2.6.2节(第67页)的练习。

因为较为简单,每个小节就只写一个练习了。

using声明易造成名字冲突:

  • 使用using声明,一般建议为每个名字做独立的using声明,例如using std::cin,不太建议使用整个命名空间,例如using namespace std,易造成名字冲突。
  • 头文件不应包含using声明:易造成名字冲突。

练习3.2

编写一段程序从标准输入中一次读入一行,然后修改该程序使其一次读入一个词。

练习3.3

请说明string类的输入运算符和getline函数分别是如何处理空白字符的。

  • 类似 cin >> str 的读取,string对象会忽略开头的空白(空格符、换行符、制表符等)并从第一个真正的字符开始读起,直到遇见下一处空白为止。
  • 类似 getline(cin, str) 的读取,string对象会从给定的输入流中读取内容,直到遇到换行符为止(换行符被读进来,但不会存放进对象)。

练习3.4

编写一段程序读取两个字符串,比较其是否相等并输出结果。如果不相等,输出较大的那个字符串。改写上述程序,比较输入的两个字符串是否等长,如果不等长,输出长度较大的那个字符串。

练习3.5

编写一段程序从标准输入中读入多个字符串并将它们连接在一起,输出连接成的大字符串。然后修改上述程序,用空格把输入的多个字符串分隔开来。

string对象操作的一些总结:

  • 定义、初始化和基本操作看下面代码(书本见P76和P77)。
  • 关系运算符<、<=、>、>=比较规则:依次比较每个位置上的字符大小,若都一样时,则长度更长的字符串就更大。
  • string和字符字面值和字符串字面值混在一条语句中,必须确保加法运算符「+」两侧至少有一个string对象(因为标准库可以将字面值转换为string对象,但不允许两个字面值直接相加)
  • size()函数返回的是string::size_type类型的值,是无符号数。表达式中如果有size(),切记不要再使用int。如果需要定义变量存储size()函数,使用autodecltype,例如auto len = str.size()
  • 注意字符串字面值不是string对象,和string是不同的类型(因为需要兼容C)。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
// 定义和初始化(等号是拷贝初始化,圆括号是直接初始化)
string s1; //默认初始化为空串
string s2(s1); // s2是s1的副本
string s2 = s1; // 同上,不过是拷贝初始化
string s3 = ("hello"); // s3是字面值"hello"的副本(不包括字面值中的空字符)
string s3 = "hello"; // 同上
string s4(n, 'c'); // s4初始化为由n个字符c组成的串

// 基本操作
os << s; // 将s写到输出流os,返回os
is >> s; // 将输入流is读取字符串赋值给s,字符串以空白分割,返回is
getline(is, s); // 从输入流is读取一行赋值给s,返回is
s.empty(); // s为空返回true,否则返回false
s.size(); // 返回s中字符的个数
s[n]; // 返回s中第n个字符的引用,下标从0计起。
s1 + s2; // 返回s1和s2连接后的结果
s1 = s2; // 用s2的副本代替s1中原来的字符
s1 == s2; // 判断两个string对象是否相等,对字母大小写敏感
s1 != s2;
<, <=, >, >= ; // 利用字符在字典中的顺序进行比较,对字母大小写敏感
阅读全文 »

第二章:变量和基本类型

练习2.1

类型 int、long、long long 和 short 的区别是什么?无符号类型和带符号类型的区别是什么?float 和 double的区别是什么?

C++ 规定 shortint 至少16位,long 至少32位,long long 至少64位。
带符号类型能够表示正数、负数和 0 ,而无符号类型只能够表示 0 和正整数。
通常,单精度float用1个字表示(4个字节,32bit),双精度double用2个字表示(8个字节,64bit)。

用法(类型的选择):

  • 如果确认数据是非负的,那么就使用 unsigned 无符号类型。
  • 一般使用 int 做整数运算,short 因为太小在实际中用的少,long 通常和 int 有着相同的大小。如果数据非常大,可以使用 long long
  • 算术表达式不用 charbool ,这二者只建议用于存放字符或布尔值。因为char在某些机器上是有符号的,在另一些机器上是无符号型的,则使用 char 进行运算容易出问题。如果需要较小的整数,就明确指定 signed char 或者 unsigned char
  • 执行浮点运算时用 double ,因为 float 通常精度不够而且双精度浮点数和单精度浮点数的计算代价相差无几。

参考:

float有效位理解

IEEE规定float为32bit,尾数用23位存储,加上隐含的小数点前的1位1,2^(23+1) = 16777216。因为 10^7 < 16777216 < 10^8,所以说单精度浮点数的有效位数是7位(能保证7位有效数字,当然,并非说第8位一定是非有效数字,它也有可能是准确的)。

1
2
3
4
5
6
7
8
9
#include <stdio.h>

int main()
{
float i = 12345678.76348;
float j = 46857.9874;
printf("%f\n%f\n%.3f\n%.8f", i, j, j, j);
return 0;
}

输出:

1
2
3
4
12345679.000000
46857.988281
46857.988
46857.98828125

从以上数据可以看出,第八个数字之后就不精确了。另外,要注意,有效数字的位数与指定输出的小数位数(%.7f,保留7位有效数字)是两码事,如第三第四个输出,这个是程序指定的输出格式,和类型本身能够存储的精度不是一回事。

C++算术类型

类型含义最小尺寸
bool布尔类型未定义
char字符8位
wchar_t宽字符16位
char16_tUnicode字符16位
char32_tUnicode字符32位
short短整型16位
int整型16位
long长整型32位
long long长整型64位
float单精度浮点数6位有效数字
double双精度浮点数10位有效数字
long double扩展精度浮点数10位有效数字

练习2.2

计算按揭贷款时,对于利率、本金和付款分别应选择何种数据类型?说明你的理由。

使用 doublefloat

练习2.3

读程序写结果。

1
2
3
4
5
6
7
8
unsigned u = 10, u2 = 42;
std::cout << u2 - u << std::endl;
std::cout << u - u2 << std::endl;
int i = 10, i2 = 42;
std::cout << i2 - i << std::endl;
std::cout << i - i2 << std::endl;
std::cout << i - u << std::endl;
std::cout << u - i << std::endl;

输出:

1
2
3
4
5
6
32
4294967264 // -32=(-1)×2^32+4294967264
32
-32
0
0

类型转换的总结

  • 非布尔类型转换布尔类型时,0转换成false,非0则true(包括负数)。
  • 布尔值转换非布尔类型时,false转换为0,true则1。
  • 浮点数转换整数时,仅保留小数点之前的部分(即整数部分,小数部分直接截断),这是精度损失;当浮点数表示的值大过整型值,会发生溢出。
  • 整数转浮点数时,小数部分记为0。不会发生溢出,但当整数值数据较大时,转换浮点数可能会发生精度丢失。例如,int 有31bit用来拓展精度,float 只有24bit,即当int值大于2^24或者小于-2^24时,转换float就会精度丢失。
  • 给无符号类型赋值超过其表示范围时,实际值是初始值对无符号类型表示数值总数取模后的余数。8bit的unsigned char表示0-255,赋值超出范围时,实际值为该值对256取模后的余数。因此将-1赋给8bit的unsigned char时,结果值为255。
  • 赋给带符号类型一个超出范围的值时,结果是未定义的。此时,程序可能工作、可能崩溃、也可能生成垃圾数据。

无符号类型和有符号类型计算,结果为负数时,结果值的计算方法

给定一个正整数p,任意一个整数n,一定存在等式n=kp+r

其中k、r是整数,且0<=r<p,称k为n除以p的商,r为n除以p的余数。

定义取模运算:a % p(或a mod p),表示a除以p的余数。

实际运用场景:将-1赋给8bit的unsigned char时,结果值为255。
计算过程:-1=(-1)×256+255

二进制表示的本质:用补码表示,先看原码(符号位为1,数值位只有一个1)对原码取反加1(符号位不变),转换成补码后,所有位都是1。

类型转换的使用场景总结

  • 不要混用带符号类型和无符号类型:表达式中含有这两种类型时,带符号数会自动转换成无符号数(此时,一个负数转换成无符号数后,真值将很大)。
  • 循环中的判断条件慎用无符号数:无符号数表示范围为正整数,不会小于0,尤其是当循环的临界条件是0时。如以下代码,就是死循环,当u=0时,循环条件依然满足,继续执行,--u就是-1,但无符号数只能表示整数,-1被自动地转换成一个合法的无符号数,即正整数。
1
2
for (unsigned u = 10; u >= 0; --u)
std::cout << u << std::endl;

解决方式:

  1. 用有符号类型
  2. 用while语句,代码如下。
  3. 类似while语句,将for语句的--u置于cout语句中。
  4. 2和3本质上就是保证u不会变为-1。
1
2
3
4
5
6
unsigned u = 11;
while (u > 0)
{
--u;
std::cout << u << std::endl;
}

练习2.4

编写程序检查你的估计是否正确,如果不正确,请仔细研读本节直到弄明白问题所在。

阅读全文 »

第一章:开始

练习1.1

查阅你使用的编译器文档,确定它所使用的文件命名约定。编译并运行第2页的main程序。

1
2
3
4
int main()
{
return 0;
}

练习1.2

改写程序,让它返回-1。返回值-1通常被当作程序错误的标识。重新编译并运行你的程序,观察你的系统如何处理main返回的错误标识。

1
2
3
4
int main()
{
return -1;
}

编译后在命令行运行程序,之后通过echo查看。

cmd: echo %ERRORLEVEL%,输出-1

bash: echo $?,输出127

练习1.3

编写程序,在标准输出上打印 Hello, World。

1
2
3
4
5
6
7
#include <iostream>

int main()
{
std::cout << "Hello, World" << std::endl;
return 0;
}

练习1.4

我们的程序使用加法运算符+来将两个数相加。编写程序使用乘法运算符*,来打印两个数的积。

1
2
3
4
5
6
7
8
9
10
11
#include <iostream>

int main()
{
std::cout << "Enter two numbers:" << std::endl;
int v1 = 0, v2 = 0;
std::cin >> v1 >> v2;
std::cout << "The product of " << v1 << " and " << v2
<< " is " << v1 * v2 << std::endl;
return 0;
}

练习1.5

我们将所有输出操作放在一条很长的语句中。重写程序,将每个运算对象的打印操作放在一条独立的语句中。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
#include <iostream>

int main()
{
std::cout << "Enter two numbers:" << std::endl;
int v1 = 0, v2 = 0;
std::cin >> v1 >> v2;
std::cout << "The product of ";
std::cout << v1;
std::cout << " and ";
std::cout << v2;
std::cout << " is ";
std::cout << v1 * v2;
std::cout << std::endl;
return 0;
}
阅读全文 »

R.I.P