本篇文章将带你重新认识C++,让你重拾少年的时候对她的激情与热爱。你认识到的编程是怎样的呢?为什么我们推荐使用C和C++?大家对于Python与Scratch有何误解?欢迎大家留言评论。
C:1973年
Developed by Dennis Richie and Ken Thompson at
Bell Labs between 1969 and 1973
C++: 1979
Created by Bjarne Stroustrup as an extension
of the C programming langguage
C语言之父:Dennis Richie
C语言之父:Ken Thompson
C++之父 Bjarne Stroustrup
C with Classes
在C语言的基础加上类classes
Renamed to C++重新命名为C++
C++标准在不断修订改变,所以呢,我们称为C+++++。
Java:1995
Java之父:James gosling
I hate memory management in C/C++!
C与C++最大的编程困难时内存管理,这是让人头痛的问题,所以我们采用Java,
Java的优点是你不用去申请内存,去手动申请与手动释放,Java有一套自己的内存管理方式帮你去做,所以Java的安全性更高。
I want “Write once,run anywhere”,not “write one,complie anywhere”.
Java的信条,Java希望在设计之初能在所有的平台上去运行,Java时跨平台的,C与C++同样是跨平台的语言,他们是在各种平台上要重新编译后才能运行。当你完成Java编码的时候,会生成一个字节码文件(中间文件),然后在所有的平台上运行。
Grammar is similar with C++.
*A java compiler generates .class files, not executable files.
Java的语法与C++很多时接近的,它可以算是C++的子集,C/C++是编译语言,它可以生成可执行程序,
而Java编译器是生成字节码的class文件,而不是可执行文件,然后用Java虚拟机读取这个字节码文件,
接着通过Java虚拟机去运行。
Pyton语言1990:
I hate grammer!
I hate too data types!
Python的年龄比Java语言还早,Python是脚本语言,脚本语言语法宽松,脚本语言没有太多复杂的语法
和数据类型,脚本语言有很多缺点,这里不详细展开。
Scratch:2002
I don’t like to type a keyboard
Scratch也是一种编程语言,因为它不需要记忆太多的语法规则,深受青少年朋友的喜爱,可以培养小学生的编程思想。
他更高级,这里的高级指的是它的编程交互能力更高级,它是一种可视化编程语言,采用Scratch编程的时候,可以不需要键盘,他定义了很多模块,你只需要把模块拖过来连接起来就是一个程序,这些模块包含for循环,if else判断,变量定义等。
C与C++标准:
C语言:
1972 Brith 1978 K&R C 1989/1990 ANSI C and ISO C 1999 C99 2011 C11 2017 C17 TBD C2
C++语言标准:
C++98 C++03 C++11,C++0x,C++14,C++1y,C++17,C++1z,C++20,C++2a
很多人被吓住,然后励志要学好C++,然后呢被C++搞得头晕,然后呢开始摆烂,最后留下悔恨的泪水。
励志学好编程的你
被C++吓住的你
搞得头晕的你
开始摆蓝的你
留下悔恨泪水的你
1、效率高Widely optimized compliers编译器优化完善。
2.Access memory directly直接访问内存
3.Excellent on computing计算效率高
4.Important language for AI algorithm impelenmentation
我们目前计算机的基础软件,包括Windows和Linux,数据库系统MySQL,计算机视觉软件OpenCV。
也有同学会讲,现在最流行的深度学习都是用的是Python,然而深度学习的框架Tensorflow、Pytorch
等等产品都是C++开发的,python调用的模块都是由C和C++实现的。python只是一个rapper,核心还是C/C++
所以只要是计算机相关专业的学生,C/C++是必学的语言。
我们不要寄托于一篇文章就能学会C++语言或者培训班的几节课,现在也没有人能够掌握C++的所有语法。
惯例以Hello World开篇,并且通过C++11完成Hello World:
#include#include #include using namespace std; int main() { vector msg{"Hello","C++","World","!"}; //msg变量中有四个元素 for (const string&word : msg) { cout< Compile编译 hello.cpp生成可执行文件
g++ hello.cppInitialization of msg is a C++11 extenstion.这里我们使用C++11最新标准
g++ hello.cpp -std=c++11Executable file can be genrated as a.out. Change the output
默认可执行文件名a.out,我们使用-o选项制定输出文件名
filename by -o optiong++ hello.cpp --std=c++11 -o helloExecute 执行程序
./hello ~/Desktop/files/c++11 ls a.out hello.cpp ~/Desktop/files/c++11 ./a.out Hello C++ World !Complie and Link编译与链接原理如果我们了解编译与链接的原理,那么在后续的编程中,我们就能快速定位错误。
main.cpp#includeusing namespace std; int mul(int a, int b) { return a * b; } int main() { int a,b; int result; cout<<"Pick two integers:"; cin>>a; cin>>b; result = mul(a,b); cout<<"The result is "< 首先mul函数有两个参数a和b,然后返回int类型,返回值是ab,主函数中我们会调用mul函数,mul函数中a与b来自标准输入cin,a和b是两个整数,那么两个右箭头表示从标准输入读数据转成整数类型存到a与b中,接着传给函数mul,mul的返回值也是a乘以b,就会存到result里面,最后我们把resutl打印出来。
这个例子里面呢,有两个知识点:
Function prototypes and definitions函数原型与声明
**function prototypes normally are put into head files(.h;.cpp)**
int mul(int a, int b);
**function definitions normally are in source files(.c;*.cpp)**int mul(int a,int b) { return a * b; }一般来说我们会把函数声明放入.h文件,或者hpp文件里,把函数的实现与定义会放到主程序中.c与.cpp文件中。如果你的程序非常大,全部放在原文件中是一件非常可怕的事情,因为编译一次会消费很长的时间,管理起来也不方便,那么我们可以把所有的源代码放在不同的文件里,分门别类去管理。
Seperate the source code into multiple files
main.cpp#include#include "mul.hpp" using namespace std; int main() { int a,b; int result; cout<<"Pick two integers:"; cin>>a; cin>>b; result =mul(a,b); cout<<"The result is "< mul.cpp
#include "mul.hpp" int mul(int a,int b) { return a * b; }mul.hpp
#pragma once int mul(int a, int b);include作用相当于是吧mul头文件包含起来,当编译器编译的时候碰到了mul,因为他不知道这是什么东西
编译器会检查头文件,从头文件中得知这是一个函数声明。那么我们如何完成三个文件的编译呢?
编译的过程,完整步骤:
g++ -c main.cpp
g++ -c mul.cpp
g++ main.o mul.o -o mul
main.cpp通过g++把它编译成main.o,o的全称是object二进制文件,-c选型的意思是只编译不链接。
从object文件生成可执行程序的步骤叫链接,实际上是将两个二进制文件并起来,-o后面输出文件的名字可以
更具你的需求更改。
我们使用g++ -c main.cpp编译程序后,在终端terminal中使用ll命令后,发现多出来的main.o文件-rwxr-xr-x 1 security staff 67K 4 30 20:50 a.out -rw-r--r--@ 1 security staff 301B 4 30 20:48 hello.cpp -rw-r--r--@ 1 security staff 236B 4 30 21:57 main.cpp -rw-r--r-- 1 security staff 14K 4 30 22:06 main.o -rw-r--r--@ 1 security staff 59B 4 30 21:59 mul.cpp -rw-r--r--@ 1 security staff 37B 4 30 22:00 mul.hpp那我们再来g++ mul.cpp -c
-rwxr-xr-x 1 security staff 67K 4 30 20:50 a.out -rw-r--r--@ 1 security staff 301B 4 30 20:48 hello.cpp -rw-r--r--@ 1 security staff 236B 4 30 21:57 main.cpp -rw-r--r-- 1 security staff 14K 4 30 22:06 main.o -rw-r--r--@ 1 security staff 60B 4 30 22:10 mul.cpp -rw-r--r--@ 1 security staff 38B 4 30 22:12 mul.hpp -rw-r--r-- 1 security staff 628B 4 30 22:12 mul.o这时候又多了一个object文件,接着我们将它们链接起来。
最后使用命令g++ main.o mul.o -o mul输出如下内容:g++ main.o mul.o -o mul ~/Desktop/files/c++11 ls a.out hello.cpp main.cpp main.o mul mul.cpp mul.hpp mul.o ~/Desktop/files/c++11 ./mul Pick two integers:2 3 The result is 6当然我们编译的时候也可以偷懒,首先删除所有.o文件,mul删除
rm *.o rm mul ll然后g++ main.cpp mul.cpp -o mul一次性把所有的源文件一次性编译完,效果是一样的,这种编译方式
会自动检测并且包含文件夹当中hpp头文件,但是编译的时间会更长。
那么我们为什么要分开编译,当我们的源文件非常多的时候,如果你每次都要把100个源文件全部编译完
那花的时间较长,如果你分别分成不同的源文件而且单独编译的话,它只需要编译obeject文件,其他的就不需要
更新,那么这样可以提高编译效率。当然我们用手动操作编译的话是话费时间的,那么其实这件事有一个工具可以协助
我们完成程序的编译,那就是利用makefile工具,这个工具在本文章后续会详细介绍,读者也可以参考目录自行跳读。
那么我们如何完成debug呢?
第一个步骤是我们需要确定错误是一个怎样的错误?错误分为三大类,第一是编译错误,
例如我们程序中少了分号main.cpp:11:18: error: expected ';' after expression result =mul(a,b) ^ ; 1 error generated.这种错误叫做编译错误,编译错误由语法造成了。main.cpp会告诉你,在第11行,第18个字符expected一个分号。
一般gcc或者g++报错会是在制定错误的前面提醒你,这个时候你就需要仔细检查源代码看看是漏了分号吗,还是大小写有问题。
第二类错误是链接错误duplicate symbol 'mul(int, int)' in: main.o mul.o ld: 1 duplicate symbol for architecture x86_64 clang: error: linker command failed with exit code 1 (use -v to see invocation)例如我们在main函数里没有包含头文件会造成链接错误,还例如程序函数名大小写有问题。我们分开编译的时候没有任何
影响,但是当我们使用g++ main.o mul.o -o mul的时候就会报错了。main.o 需要mul这个符号,你在头文件中说
你有,但是在main中并没有,编译器认为你是骗子,那么我就不能继续编译了。
第三类错误:运行式错误
运行式错误指:你成功编译了,也成功链接了,但是在运行的时候程序就崩掉了。
下面呈现一个运行式错误runtime error#include "mul.hpp" int mul(int a,int b) { int c = a / b; return a * b; }我么在 mul.cpp程序中加入int c = a/b;
函数与参数都没有问题,但是b=0,程序如何处理,程序就会抛出异常,异常直接将程序杀死掉.Pick two integers:2 0 [2] 6086 floating point exception ./mul大家可以观察到程序已经被杀死,所以当我们在完成程序设计的时候需要细心,当你写下a/b的时候就要考虑到异常问题。
那么看到这里本文还未结束征程,博主码字不易求各位姥爷一个三连。
参考:南方科技大学于仕琪副教授的课堂讲义,文章稍有偏差。
申明:原作者仕琪副教授使用CC协议,本文继承采用CC协议,允许转载,非商业使用。



