个人网站用主机做服务器,网页设计与制作教程第二版知识点总结,模版网站系统,网站极简设计个人主页#xff1a;C忠实粉丝 欢迎 点赞#x1f44d; 收藏✨ 留言✉ 加关注#x1f493;本文由 C忠实粉丝 原创 C基础入门(上) 收录于专栏【C语法基础】 本专栏旨在分享学习C的一点学习笔记#xff0c;欢迎大家在评论区交流讨论#x1f48c; 目录
1. C发展历史
2. C版本… 个人主页C忠实粉丝 欢迎 点赞 收藏✨ 留言✉ 加关注本文由 C忠实粉丝 原创 C基础入门(上) 收录于专栏【C语法基础】 本专栏旨在分享学习C的一点学习笔记欢迎大家在评论区交流讨论 目录
1. C发展历史
2. C版本更新
3. C参考⽂档
4. C的重要性
4.1 编程语⾔排⾏榜
4.2 C在⼯作领域中的应⽤
5. 学习书籍推荐
6. C的第一个程序 7.命名空间
7.1namespace的价值
7.2namespace的定义
7.3 命名空间使⽤
8. C输⼊输出 9. 缺省参数 1. C发展历史
C的起源可以追溯到1979年当时BjarneStroustrup(本贾尼·斯特劳斯特卢普这个翻译的名字不 同的地⽅可能有差异)在⻉尔实验室从事计算机科学和软件⼯程的研究⼯作。⾯对项⽬中复杂的软件开 发任务特别是模拟和操作系统的开发⼯作他感受到了现有语⾔如C语⾔在表达能⼒、可维护性 和可扩展性⽅⾯的不⾜。 1983年BjarneStroustrup在C语⾔的基础上添加了⾯向对象编程的特性设计出了C语⾔的雏形 此时的C已经有了类、封装、继承等核⼼概念为后来的⾯向对象编程奠定了基础。这⼀年该语⾔被 正式命名为C。 在随后的⼏年中C在学术界和⼯业界的应⽤逐渐增多。⼀些⼤学和研究所开始将C作为教学和研 究的⾸选语⾔⽽⼀些公司也开始在产品开发中尝试使⽤C。这⼀时期C的标准库和模板等特性 也得到了进⼀步的完善和发展。 C的标准化⼯作于1989年开始并成⽴了⼀个ANSI和ISOInternationalStandards Organization国际标准化组织的联合标准化委员会。1994年标准化委员会提出了第⼀个标准化草 案。在该草案中委员会在保持斯特劳斯特卢普最初定义的所有特征的同时还增加了部分新特征。 在完成C标准化的第⼀个草案后不久STLStandardTemplateLibrary是惠普实验室开发的⼀系 列软件的统称。它是由AlexanderStepanov、MengLee和DavidRMusser在惠普实验室⼯作时所开发 出来的。在通过了标准化第⼀个草案之后联合标准化委员会投票并通过了将STL包含到C标准中的 提议。STL对C的扩展超出C的最初定义范围。虽然在标准中增加STL是个很重要的决定但也因 此延缓了C标准化的进程。 1997年11⽉14⽇联合标准化委员会通过了该标准的最终草案。1998年C的ANSI/IS0标准被投⼊使⽤。
2. C版本更新
3. C参考⽂档
参考 - C 参考 (cplusplus.com)
C 参考手册 - cppreference.com
cppreference.com 说明第⼀个链接不是C官⽅⽂档标准也只更新到C11但是以头⽂件形式呈现内容⽐较易看 好懂。后两个链接分别是C官⽅⽂档的中⽂版和英⽂版信息很全更新到了最新的C标准但是 相⽐第⼀个不那么易看⼏个⽂档各有优势我们结合着使⽤。 4. C的重要性
4.1 编程语⾔排⾏榜
TIOBE排⾏榜是根据互联⽹上有经验的程序员、课程和第三⽅⼚商的数量并使⽤搜索引擎如 Google、Bing、Yahoo!以及Wikipedia、Amazon、YouTube和Baidu百度统计出排名数据只 是反映某个编程语⾔的热⻔程度并不能说明⼀⻔编程语⾔好不好或者⼀⻔语⾔所编写的代码数量多少。
4.2 C在⼯作领域中的应⽤
C的应⽤领域服务器端、游戏引擎、机器学习引擎、⾳视频处理、嵌⼊式软件、电信设备、⾦融 应⽤、基础库、操作系统、编译器、基础架构、基础⼯具、硬件交互等很多⽅⾯都有。
1. ⼤型系统软件开发。如编译器、数据库、操作系统、浏览器等等
2. ⾳视频处理。常⻅的⾳视频开源库和⽅案有FFmpeg、WebRTC、Mediasoup、ijkplayer⾳视频 开发最主要的技术栈就是C。
3. PC客⼾端开发。⼀般是开发Windows上的桌⾯软件⽐如WPS之类的技术栈的话⼀般是C和 QTQT是⼀个跨平台的C图形⽤⼾界⾯GraphicalUserInterfaceGUI程序。
4. 服务端开发。各种⼤型应⽤⽹络连接的⾼并发后台服务。这块Java也⽐较多C主要⽤于⼀些对性能要求⽐较⾼的地⽅。如游戏服务、流媒体服务、量化⾼频交易服务等
5. 游戏引擎开发。很多游戏引擎就都是使⽤C开发的游戏开发要掌握C基础和数据结构学习 图形学知识掌握游戏引擎和框架了解引擎实现引擎源代码可以学习UE4、Cocos2d-x等开源 引擎实现
6. 嵌⼊式开发。嵌⼊式把具有计算能⼒的主控板嵌⼊到机器装置或者电⼦装置的内部通过软件能够 控制这些装置。⽐如智能⼿环、摄像头、扫地机器⼈、智能⾳响、⻔禁系统、⻋载系统等等粗略⼀点嵌⼊式开发主要分为嵌⼊式应⽤和嵌⼊式驱动开发。
7. 机器学习引擎。机器学习底层的很多算法都是⽤C实现的上层⽤python封装起来。如果你只想准备数据训练模型那么学会Python基本上就够了如果你想做机器学习系统的开发那么需要学会C。
8. 测试开发/测试。每个公司研发团队有研发就有测试测试主要分为测试开发和功能测试测试 开发⼀般是使⽤⼀些测试⼯具(selenium、Jmeter等)设计测试⽤例然后写⼀些脚本进⾏⾃动化测试性能测试等有些还需要⾃⾏开发⼀些测试⽤具。功能测试主要是根据产品的功能设计测试⽤例然后⼿动的⽅式进⾏测试。
5. 学习书籍推荐
CPrimer主要讲解语法经典的语法书籍前后中期都可以看前期如果⾃学看可能会有点晦涩 难懂能看懂多少看懂多少就当预习学了⽐特课程后中后期作为语法字典⾮常好⽤。 STL源码剖析主要从底层实现的⻆度结合STL源码庖丁解⽜式剖析STL的实现是侯捷⽼师的经典 之作。可以很好的帮助我们学习别⼈⽤语法是如何实现出⾼效简洁的数据结构和算法代码如何使⽤ 泛型封装等。让我们不再坐井观天闭⻔造⻋中后期可以看。 Effctive C本书也是侯捷⽼师翻译的本书有的⼀句评价把C程序员分为看过此书的和没看过此书的。本书主要讲了55个如何正确⾼效使⽤C的条款建议中后期可以看⼀遍⼯作1-2年后再看 ⼀遍相信会有不⼀样的收获。
6. C的第一个程序
C兼容C语⾔绝⼤多数的语法所以C语⾔实现的helloworld依旧可以运⾏C中需要把定义⽂件 代码后缀改为.cppvs编译器看到是.cpp就会调⽤C编译器编译linux下要⽤g编译不再是gcc // test.cpp#includestdio.hint main(){printf(hello world\n);return 0;} 当然C有⼀套⾃⼰的输⼊输出严格说C版本的helloworld应该是这样写的。 // test.cpp// 这⾥的std cout等我们都看不懂没关系下⾯会依次讲解
#includeiostream
using namespace std;int main()
{cout hello world\n endl;return 0;
} 7.命名空间
7.1namespace的价值
在C/C中变量、函数和后⾯要学到的类都是⼤量存在的这些变量、函数和类的名称将都存在于全 局作⽤域中可能会导致很多冲突。使⽤命名空间的⽬的是对标识符的名称进⾏本地化以避免命名冲突或名字污染namespace关键字的出现就是针对这种问题的。
c语⾔项⽬类似下⾯程序这样的命名冲突是普遍存在的问题C引⼊namespace就是为了更好的解决这样的问题 #include stdio.h
#include stdlib.hint rand 10;int main()
{// 编译报错error C2365 : “rand”:重定义以前的定义是“函数”printf(%d\n, rand);return 0;
}
7.2namespace的定义
• 定义命名空间需要使⽤到namespace关键字后⾯跟命名空间的名字然后接⼀对{}即可{}中即为命名空间的成员。命名空间中可以定义变量/函数/类型等。
• namespace本质是定义出⼀个域这个域跟全局域各⾃独⽴不同的域可以定义同名变量所以下⾯的rand不在冲突了。
• C中域有函数局部域全局域命名空间域类域域影响的是编译时语法查找⼀个变量/函数/ 类型出处(声明或定义)的逻辑所有有了域隔离名字冲突就解决了。局部域和全局域除了会影响 编译查找逻辑还会影响变量的声明周期命名空间域和类域不影响变量生命周期。 #include stdio.h
#include stdlib.hnamespace yu
{int rand 10;
}int a 0;
int main()
{printf(%p\n, rand);printf(%d\n, yu::rand);int a 1;printf(%d\n, a);//::域作用限定符printf(%d\n,::a);return 0;
} • namespace只能定义在全局当然他还可以嵌套定义。 #include stdio.h
#include stdlib.h// 域
namespace yu
{namespace ld{int rand 1;int Add(int left, int right){return left right;}}// 杭哥namespace lr{int rand 2;int Add(int left, int right){return (left right) * 10;}}
}int main()
{printf(%d\n, yu::ld::rand);printf(%d\n, yu::ld::Add(1,2));printf(%d\n, yu::lr::rand);printf(%d\n, yu::lr::Add(1,2));return 0;
} • 项⽬⼯程中多⽂件中定义的同名namespace会认为是⼀个namespace不会冲突。
比如我们可以定义一个栈的头文件和cpp文件 #includestdio.h
#includestdlib.h
#includestdbool.h
#includeassert.hnamespace Mystack
{typedef int STDataType;typedef struct Stack{STDataType* a;int top;int capacity;}ST;void STInit(ST* ps, int n 4);void STDestroy(ST* ps);void STPush(ST* ps, STDataType x);void STPop(ST* ps);STDataType STTop(ST* ps);int STSize(ST* ps);bool STEmpty(ST* ps);
} #includeStack.hnamespace Mystack
{void STInit(ST* ps, int n){assert(ps);ps-a (STDataType*)malloc(n * sizeof(STDataType));ps-top 0;ps-capacity n;}// ջvoid STPush(ST* ps, STDataType x){assert(ps);// ˣ if (ps-top ps-capacity){printf(\n);int newcapacity ps-capacity 0 ? 4 : ps-capacity* 2;STDataType* tmp (STDataType*)realloc(ps-a,newcapacity * sizeof(STDataType));if (tmp NULL){perror(realloc fail);return;}ps-a tmp;ps-capacity newcapacity;}ps-a[ps-top] x;ps-top;}//...在main主函数中再次定义一个栈 #includeStack.h// 全局定义了一份单独的Stack
typedef struct Stack
{int a[10];int top;
}ST;
void STInit(ST* ps) {}
void STPush(ST* ps, int x) {}int main()
{// 调用全局的ST st1;STInit(st1);STPush(st1, 1);STPush(st1, 2);printf(%d\n, sizeof(st1));// 调用Mystack namespace的Mystack::ST st2;printf(%d\n, sizeof(st2));Mystack::STInit(st2, 4);Mystack::STPush(st2, 1);Mystack::STPush(st2, 2);return 0;
} 程序会调用不同命名空间的栈进行计算
• C标准库都放在⼀个叫std(standard)的命名空间中。 #include iostream
#include stringint main() {std::string message Hello, World!;std::cout message std::endl;return 0;
} 在这个例子中
std::string 是 std 命名空间中的 string 类型。std::cout 是 std 命名空间中的 cout 对象用于标准输出。
如果没有使用命名空间 std而是直接使用 cout 或 string则需要添加额外的声明或者会出现编译错误因为这些标识符在全局命名空间中通常是未定义的或者与其他库发生冲突。
7.3 命名空间使⽤
编译查找⼀个变量的声明/定义时默认只会在局部或者全局查找不会到命名空间⾥⾯去查找。所以下⾯程序会编译报错。所以我们要使⽤命名空间中定义的变量/函数
有三种⽅式
• 指定命名空间访问项⽬中推荐这种⽅式。
• using将命名空间中某个成员展开项⽬中经常访问的不存在冲突的成员推荐这种⽅式。
• 展开命名空间中全部成员项⽬不推荐冲突⻛险很⼤⽇常⼩练习程序为了⽅便推荐使⽤。 //展开头文件
#include stdio.h
namespace My_yu
{int a 0;int b 1;
}//using namespace My_yu; 全部展开
using My_yu::a; //展开部分int main()
{printf(%d\n, a);printf(%d\n, a);printf(%d\n, a);printf(%d\n, a);printf(%d\n, a);printf(%d\n, a);printf(%d\n, My_yu::b);return 0;
} 8. C输⼊输出
• iostream是InputOutputStream的缩写是标准的输⼊、输出流库定义了标准的输⼊、输 出对象。
• std::cin 是istream类的对象它主要⾯向窄字符narrowcharacters(oftypechar)的标准输 ⼊流。
• std::cout 是ostream类的对象它主要⾯向窄字符的标准输出流。
• std::endl 是⼀个函数流插⼊输出时相当于插⼊⼀个换⾏字符加刷新缓冲区。
• 是流插入运算符,是流提取运算符。C语⾔还⽤这两个运算符做位运算左移/右移
• 使⽤C输⼊输出更⽅便不需要像printf/scanf输⼊输出时那样需要⼿动指定格式C的输⼊ 输出可以⾃动识别变量类型(本质是通过函数重载实现的这个以后会讲到)其实最重要的是 C的流能更好的⽀持⾃定义类型对象的输⼊输出。
• IO流涉及类和对象运算符重载、继承等很多⾯向对象的知识这些知识我们还没有讲解所以这⾥我们只能简单认识⼀下CIO流的⽤法后⾯会出专⻔的⼀个章节来细节IO流库。
• cout/cin/endl等都属于C标准库C标准库都放在⼀个叫std(standard)的命名空间中所以要 通过命名空间的使⽤⽅式去⽤他们。
• ⼀般⽇常练习中我们可以using namespace std实际项⽬开发中不建议using namespace std。
• 这⾥我们没有包含stdio.h也可以使⽤printf和scanf在包含间接包含了。vs系列编译器是这样的其他编译器可能会报错。 #includeiostream
using namespace std;int main()
{int i 1234;int j -1234;std::cout i endl;cout i endl; 自动识别类型: #includeiostream
using namespace std;int main()
{int a 0;double b 0.1;char c x;cout a b c \n \n endl;std::cout a b c std::endl;scanf(%d%lf, a, b);printf(%d %lf\n, a, b);// 可以自动识别变量的类型//cin a;//cin b c;cin a b c;cout a endl;cout b c endl;return 0;
} ios_base::sync_with_stdio(false); 默认情况下C 的输入输出流与 C 标准输入输出流是同步的这意味着在使用 cin 和 cout 时它们会在每次读取或写入后都尝试刷新相关的缓冲区。这种同步可能会导致性能上的损失特别是在大量的输入输出操作中。通过将 sync_with_stdio 设置为 false你告诉 C 不要与 C 的标准输入输出流同步从而可以获得更好的性能因为 C 的流可以使用更高效的缓冲机制。 cin.tie(nullptr); 和 cout.tie(nullptr); 默认情况下cin 和 cout 是关联的这意味着当你使用 cin 进行输入时cout 的缓冲区会被刷新以确保输出先于输入显示通常不需要显式刷新因为输入操作会自动刷新输出缓冲区。将 cin.tie(nullptr); 和 cout.tie(nullptr); 设置为 nullptr你断开了 cin 和 cout 之间的关联。这可以防止不必要的缓冲区刷新进一步提高输入输出的效率尤其是在需要处理大量数据时。 #includeiostream
using namespace std;int main()
{// 在io需求比较高的地方如部分大量输入的竞赛题中加上以下3行代码// 可以提高CIO效率ios_base::sync_with_stdio(false);cin.tie(nullptr);cout.tie(nullptr);return 0;
}9. 缺省参数
• 缺省参数是声明或定义函数时为函数的参数指定⼀个缺省值。在调⽤该函数时如果没有指定实参 则采⽤该形参的缺省值否则使⽤指定的实参缺省参数分为全缺省和半缺省参数。有些地⽅把 缺省参数也叫默认参数
• 全缺省就是全部形参给缺省值半缺省就是部分形参给缺省值。C规定半缺省参数必须从右往左依次连续缺省不能间隔跳跃给缺省值。
• 带缺省参数的函数调⽤C规定必须从左到右依次给实参不能跳跃给实参。
• 函数声明和定义分离时缺省参数不能在函数声明和定义中同时出现规定必须函数声明给缺省 值。 #include iostream
using namespace std;void Func(int a 0)
{cout a endl;
}int main()
{Func(); // 没有传参时使用参数的默认值Func(10); // 传参时使用指定的实参return 0;
} #include iostream
using namespace std;void Func(int a 0)
{cout a endl;
}// 全缺省
void Func1(int a 10, int b 20, int c 30)
{cout a a endl;cout b b endl;cout c c endl endl;
}// 半缺省
//C规定半缺省参数必须从右往左 依次连续缺省不能间隔跳跃给缺省值。
void Func2(int a, int b 10, int c 20)
{cout a a endl;cout b b endl;cout c c endl endl;
}int main()
{//带缺省参数的函数调⽤C规定必须从左到右依次给实参不能跳跃给实参。Func(); // 没有传参时使用参数的默认值Func(10); // 传参时使用指定的实参Func1();Func1(1);Func1(1, 2);Func1(1, 2, 3);//Func2();Func2(100);Func2(100, 200);Func2(100, 200, 300);return 0;
} void STInit(ST* ps, int n 4);//函数声明和定义分离时缺省参数不能在函数声明和定义中同时出现规定必须函数声明给缺值。
void STInit(ST* ps, int n)
{assert(ps);ps-a (STDataType*)malloc(n * sizeof(STDataType));ps-top 0;ps-capacity n;
}#includeiostream
using namespace std;#includeStack.hint main()
{Mystack::ST s1;Mystack::STInit(s1);// 确定知道要插入1000个数据初始化时一把开好避免扩容Mystack::ST s2;Mystack::STInit(s2, 1000);for (size_t i 0; i 1000; i){Mystack::STPush(s2, i);}return 0;
}