读《TCPL》I

The C Programming language》 -- Brian W. Kernighan / Dennis M. Ritchie 


相关笔记:《C和指针》摘录笔记  读《TCPL》II


看电子书是一件非常辛苦的事情。需要长时间的坐在电脑面前,在冬天里还需要牺牲一只手去移动鼠标或者电脑的下滑键(自动翻页只适合小说,看The  C  Programming  language 在某些地方还得停下来)。英文还不是很好and书还是英文的,很多不知道的地方估计都以脑海空白的形式略过了。书还是看纸质的比较好,没那么累,尤其对于一个做一件事情完全没有节制的人来说。


怎么个没节制法呢,花了两天将《The  C  Programming  language》浏览完了。现在的感觉是极度疲劳。坚持电子档而不去打印纸质的原因是PDF有签字功能,将书中看到的“不熟悉的”、“觉得重要的”、“实践中需要常查阅的”、“具启蒙意义的”都给标志在书签里,然后将其整理成笔记。由于学习过C语言课程后,很长的一段时间(一两年)都没有看过进阶方面的书籍,开始看书后,看的第一本也不是这本《C圣经》,其它书籍的很多原型在这本书中都应该找得到。这算是学习C语言的一个弯路。虽然在实践中将一些部分(如指针概念)搞清楚了,毕竟个人的悟性还是带有局限性。前辈们整理的“优秀”书籍对后代人具有启蒙意义,学到的不仅是未知、深入部分的知识。所以,不管眼下在做什么事情,千万不要忘记要多看“优秀的书籍”,不管哪个领域。看“优秀书籍”是进步的灵魂,如果你不是天才的话。


The C Programming language》, By Brian W.Kernig han and Dennis M.Rithie

1.C语言程序从main处开始执行(mainC语言程序的入口)。

2. 经声明(declared)的C变量才可被C程序使用。

3.intshortlongdouble等基本数据类型占内存的字节数依靠具体的平台(如win32int4 bytes)。

4.‘%’(如用于printf中)表示紧跟其后的类型由实参代替。“%%”表示输出‘%’本身(printf)。

5.‘c’’0’~’9’之间的字符,则++num[c-‘0’]实现c-‘0’数字的个数为num[c-‘0’]

6.C程序中,函数参数传值方式是一个拷贝过程。实参传递给形参时,就相当于给一个局部变量赋值。

7.字符串数组以’\0’字符结尾。’\0’对字符数组来说是一个很有用的标识。很多函数要依靠此标识来判断字符串是否结束。C语言中没有提供关于字符串数组的任何操作符,唯有通过指针来操作字符串数组。

8. 为什么不同类型(全局,局部,const)的变量的访问性不同。是硬件还是软件的作用

9.C程序的内部变量名最多可以有31个字符。外部变量名和函数名必须少于31个字符。自定义标识符不可以与C语言中的32个关键字同名。

10.一个字符常量是一个整数(ASCII值存于内存中)。

11.成对的双引号所引的字符串中可以在嵌套由成对双引号引起的字符串。若要单表示一个双引号时需要用“\””的形式。

12.要检查当前系统执行语句是从左到右还是从右到左。不然可能会引起严重错误。

13.将数字字符串转换为对应的数字时可以从高位算起。当还有下一个数字时,将原来得到的数字再乘以10加上当前个位的数字即可。

14.x指定几位的算法:x >> (p+1 – n) & ~(~0<< n)

15.运算符的优先级及结合性。可供读他人程序。

一元运算符、复合运算符及条件运算符的结合性由右至左。


16. “{}”的作用是组织声明和其他语句到一块形成一个复合语句(语句块)。


17. switch-case组合时,switch(c)中,c只可以是整型、字符型变量或表达式。case后面必须跟整型、字符型的“常量值”。case之间的值不可相同。因为const限制的变量是只读不为常量,故而const修饰的量也不能跟在case之后。


18. break语句可用于whilefordo-while循环结构中和switch-case结构中。continue只可以用于循环结构中。


20. register只可修饰自动变量和函数参数,数据类型要符合寄存器可支持的类型。register修饰的变量数目不可过多,且不可对register修饰的变量做&操作(取地址)。


21. C程序中,未初始化的全局变量和静态变量都系统自动赋值为0。自动变量和寄存器变量不会被初始化任何值(不定值)。在全局区初始化全局变量必须用常量或常量表达式。但对于整形和字符数组来说,不管哪一种类型,在初始化一部分数组元素后其余元素都为0


22. 预处理。#include <filename>#include ”filename”是将以各自方式找到的filename文件的内容来代替#include……语句。#define定义的宏除了注意给参数加括号外,给整体宏外加一层括号也是防错的必要手段。有的语句如sizeof不能够定义在诸如#undef内,编译器不会编译此下的内容。

系统已经定义的宏:

  • __LINE__当前代码的行数。

  • __FILE__当前正被编译文件的文件名。

  • __DATE__"Mmmm dd yyyy"格式显示日期的字符串。

  • __TIME__"hh:mm:ss"格式显示时间的字符串。

  • __STDC__值为1。若STDC值为1只在标准模式下。


23. void *p指针可以指向任何类型的数据,但是不可以指向void数据。“%p”就是void *类型。


24. 指针比数组块,但指针比较难用。对于指针效率很高的原因:C语言中赋值、传值都是采用拷贝的形式。对于大量数据而言,有了指针就可以只将数据的首地址传给指针,然后用指针访问到数据,避免数据拷贝。既节约空间也节约拷贝的时间。数组作为函数参数时,传递的实参数据块将地址传递给形参,形参被译为指针。所有的a[i]形式都会被编译成*(a+i)形式。


25. 指针若指向某块type数据,指针的加1操作表示地址向前sizeof(type)个字节即指向下个数据元素。


26. 0常被用作地址无效的标志。NULL被定义在stdio.h中,值为0NULL作为一种助记符,对于指针来说是一个特殊的值。EOF被定义在stdio.h中,值为-1。作为文件结束的助记符。


27. 阅读C语言中的声明从变量名开始着手。熟悉一般的声明。可编写程序自动识别声明。


28. 可在常数后面加上数据的类型。如3.1f就明确的标明了3.1为浮点类型


29. 重定向符’<’’>’表示程序接受输入、输出的流发生了变化。如prog < infile表示prog程序从infile文件内接受输入的数据。管道’|’也能实现重定向,otherprog | prog表示同时执行otherprogprogotherprog的输出作为prog的输入。


30. 可变参数函数的实现依靠:va_listva_startva_argva_end实现。va_list定义的变量用来指向参数列表的每一个参数;va_start宏用来指引va_list变量指向下一个参数(必须先使va_list变量指向已知的变量参数);va_arg用数据类型决定返回类型并决定va_list变量的步长;va_end做清理工作,最后调用。


31. systemconst char *s)。执行s


32. void *calloc(size_t n, size_t size);分配n个数量的每个大小为size的内存块。内存块被初始化为0


33. rand()创造浮点数空间、整数空间。与srand()的连用。


34. 对于unix系统,一切皆是文件。


35. Unix之上的系统调用(想起linux之上用汇编程序实现的系统调用,用标识号)。C语言实现系统调用是通过函数的名称。

  • read ----从文件标识符参数对应的文件中最多读指定长度的数据到缓冲区中。
  • write ---- 将缓冲区的数据向文件标识符参数对应的文件中写入。

  • open ---- 以指定模式打开文件标识符代表的文件。

  • close ---- 关闭文件标识符代表的文件。

  • create --- 创建文件。

  • unlink ---- 移除文件。

  • lseek ---- 随意定位文件中的内容。

Windows之上将这些函数称为非缓冲文件系统。


36. C32个关键字中。volatile关键字较为陌生。


37. C标准库和C语言的关系。

C标准库由ANSI规定,它不是C语言的一部分。C标准库是支持标准C的一个库环境,很多的函数和宏都被定义在这些库里。在C标准库中,主要有以下15个库:

<assert.h>
<float.h>
<math.h>
<stdarg.h>
<stdlib.h>
<ctype.h>
<limits.h>
<setjmp.h>
<stddef.h>
<string.h>
<errno.h>
<locale.h>
<signal.h>
<stdio.h>
<time.h>


对主要的库笔记如下:

  • <stdio.h>:常见的输入/输出函数、数据类型及宏都定义在此库中。此库约占C标准库的三分之一。size_t就是被定义在<stdio.h>中的unsigned类型。关于输入/输出的函数都可以到<stdio.h>中查询函数运行
  • <ctype.h>:字符测试函数都在此库里,包括isdigit()等函数。

  • <string.h>:关于字符串两个组别的函数,一类以str开头,如strlen();另一类以mem开头,如memcpy()

  • <math.h>:数学函数库和相关宏的定义之处。如sin()

  • <stdlib.h>:数据转换、内存管理及类似的函数库。如atof()malloc()/free()等。

  • <assert.h>:用于程序断言。宏assert()

  • <stdarg.h>:包含va_listva_startva_argva_end类型的库。

  • <setjmp.h>:提供函数函数跳转函数。setjmplongjmp

  • <signal.h>:提供处理的函数。如signal()函数。

  • <time.h>:提供函数和类型处理日期和时间。

  • <limit.h>:提供各数据类型的范围的宏定义。

  • <float.h>:浮点数据的宏。


38. The  C ProgrammingLanguage的例子重点留给第二次看这本书的时候。


R《TCPL》Note Over。

  • 1
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
很抱歉,我不是一个可以运行代码的程序,无法为您提供完整的源代码和报告。但我可以简要介绍如何在NS3中编写纺锤型网络,并使用不同的拥塞控制算法进行性能测试。 1. 编写纺锤型网络 在NS3中,我们可以使用TopologyHelper类来构建网络拓扑。对于八个节点的纺锤型网络,可以按照以下方式实现: ``` Ptr<Node> n0 = CreateObject<Node>(); Ptr<Node> n1 = CreateObject<Node>(); Ptr<Node> n2 = CreateObject<Node>(); Ptr<Node> n3 = CreateObject<Node>(); Ptr<Node> n4 = CreateObject<Node>(); Ptr<Node> n5 = CreateObject<Node>(); Ptr<Node> n6 = CreateObject<Node>(); Ptr<Node> n7 = CreateObject<Node>(); // 创建点对节点 PointToPointHelper pointToPoint; pointToPoint.SetDeviceAttribute("DataRate", StringValue("5Mbps")); pointToPoint.SetChannelAttribute("Delay", StringValue("2ms")); // 设置节点之间的连接 NetDeviceContainer devices; devices.Add(pointToPoint.Install(n0, n1)); devices.Add(pointToPoint.Install(n1, n2)); devices.Add(pointToPoint.Install(n2, n3)); devices.Add(pointToPoint.Install(n3, n4)); devices.Add(pointToPoint.Install(n4, n5)); devices.Add(pointToPoint.Install(n5, n6)); devices.Add(pointToPoint.Install(n6, n7)); devices.Add(pointToPoint.Install(n7, n0)); // 安装网络协议栈 InternetStackHelper stack; stack.InstallAll(); ``` 上述代码中,我们创建了八个节点,并使用PointToPointHelper类创建点对点的连接。接下来,我们将八个节点两两相连,构成一个纺锤型网络。最后,我们使用InternetStackHelper类安装网络协议栈。 2. 使用不同的拥塞控制算法 NS3提供了多种拥塞控制算法,例如TCP NewReno、TCP Vegas、TCP Cubic等。我们可以在仿真程序中选择不同的算法来测试其性能。 ``` // 创建Socket和Application uint16_t port = 50000; Address sinkAddress(InetSocketAddress(Ipv4Address::GetAny(), port)); PacketSinkHelper packetSinkHelper("ns3::TcpSocketFactory", sinkAddress); ApplicationContainer sinkApps = packetSinkHelper.Install(nodes.Get(0)); sinkApps.Start(Seconds(0.0)); sinkApps.Stop(Seconds(simulationTime + 0.1)); OnOffHelper onoff("ns3::TcpSocketFactory", sinkAddress); onoff.SetAttribute("OnTime", StringValue("ns3::ConstantRandomVariable[Constant=1]")); onoff.SetAttribute("OffTime", StringValue("ns3::ConstantRandomVariable[Constant=0]")); onoff.SetAttribute("DataRate", DataRateValue(DataRate("5Mbps"))); onoff.SetAttribute("PacketSize", UintegerValue(1000)); // 安装TCP协议 Config::SetDefault("ns3::TcpSocket::SegmentSize", UintegerValue(1000)); Config::SetDefault("ns3::TcpSocketBase::MaxWindowSize", UintegerValue(50000)); Config::SetDefault("ns3::TcpL4Protocol::SocketType", StringValue("ns3::TcpNewReno")); ApplicationContainer clientApps = onoff.Install(nodes.Get(1)); clientApps.Start(Seconds(0.0)); clientApps.Stop(Seconds(simulationTime + 0.1)); ``` 上述代码中,我们创建了一个TCP Socket和一个TCP Application,并使用不同的拥塞控制算法来测试网络性能。在这里,我们选择了TCP NewReno算法。使用Config::SetDefault()函数可以设置TCP Socket的一些参数,例如最大窗口大小等。 3. 性能测试和报告 在仿真程序中,我们可以使用Simulator::Run()函数来运行仿真。在仿真结束后,我们可以获取一些性能指标,例如吞吐量、延迟、丢包率等,并根据这些指标来评估不同的拥塞控制算法。 ``` Simulator::Stop(Seconds(simulationTime + 0.1)); Simulator::Run(); // 获取性能指标 uint64_t totalPacketsThrough = DynamicCast<PacketSink>(sinkApps.Get(0))->GetTotalRx(); double throughput = totalPacketsThrough * 8 / (simulationTime * 1000000.0); // Mbps double avgDelay = 0; for (uint32_t i = 0; i < clientApps.GetN(); ++i) { Ptr<OnOffApplication> onoffApp = DynamicCast<OnOffApplication>(clientApps.Get(i)); Time startTime = onoffApp->GetStartTime(); Time stopTime = onoffApp->GetStopTime(); double thisDelay = (stopTime.GetSeconds() - startTime.GetSeconds()) * 1000.0; avgDelay += thisDelay; } avgDelay /= clientApps.GetN(); // ms uint64_t totalPacketsDropped = DynamicCast<PacketSink>(sinkApps.Get(0))->GetLost(); double packetLossRate = totalPacketsDropped * 1.0 / totalPacketsThrough; // 输出性能指标 std::cout << "Throughput: " << throughput << " Mbps" << std::endl; std::cout << "Average Delay: " << avgDelay << " ms" << std::endl; std::cout << "Packet Loss Rate: " << packetLossRate * 100 << "%" << std::endl; ``` 上述代码中,我们获取了网络的吞吐量、平均延迟和丢包率等性能指标,并输出到控制台。 根据上述代码,我们可以编写出完整的仿真程序,并根据不同的拥塞控制算法进行测试。在测试中,我们可以使用如下代码切换不同的拥塞控制算法: ``` Config::SetDefault("ns3::TcpL4Protocol::SocketType", StringValue("ns3::TcpNewReno")); // 使用TCP NewReno算法 Config::SetDefault("ns3::TcpL4Protocol::SocketType", StringValue("ns3::TcpVegas")); // 使用TCP Vegas算法 Config::SetDefault("ns3::TcpL4Protocol::SocketType", StringValue("ns3::TcpCubic")); // 使用TCP Cubic算法 ``` 最终,我们可以根据实验结果,撰写不同拥塞控制算法对网络性能的影响的详细报告。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值