C++ 是一门强大而复杂的编程语言,它有其独特的应用场景和优势,尽管它可能在学习和使用上有一些挑战,但仍然被广泛采用的原因有很多,尽管 C++ 有其优势,但它也确实有一些复杂性和潜在的陷阱,因此在选择使用它时需要权衡。对于一些应用场景,其他编程语言,如Python、Java 或C#,可能更容易上手并且更适合。选择使用 C++ 还取决于你的具体项目需求、团队技能和资源可用性。
转眼间已经毕业几年了,在大学里一直使用的是Java做的很多项目,参加很多比赛做的项目也是Java+Spring Boot做的后端,谈到这里就想到了很多很多回忆.什么IOC,什么Docker,什么Mybtis源码当时真的贼熟.
在大学里还做了一个开源项目:https://github.com/truedei/truedei-swagger-plugin
甚至大四实习时也是使用的Java做后端开发
为什么我毕业后却找了C语言和C++相关的工作呢?请跟随脚步,继续往下看.
文字有点多,耐心一些,文末送几本书大家可以看下.
踏入大学的后,计算机相关专业同学大多入门的编程课都是C语言,然后慢慢进阶到C++/Java/Python等高级语言.为什么会先学C,为什么不直接学习Java或者C++呢?听到的很多回答的声音都是一致认为:
C++ 是一门广泛应用的编程语言,许多组织和领域都在使用它。小到嵌入式,大到各种服务器,到处都可以见到C++的身影. 以下是一些主要领域和用途:
C++ 是一门多用途的编程语言,由于其性能、控制力和跨平台能力,被广泛应用于各种不同的领域和行业。虽然它有一些复杂性,但在需要高性能和底层控制的应用中,仍然是一个强大的选择。
为什么我毕业后却找了C语言和C++相关的工作呢?现在就揭晓答案.
原因是:就在即将毕业的前夕,还有2-3周就要离校了. 其实我已经找好工作了,北京,上海,深圳都拿到了面试的Offer.深圳拿到了20多K也是很不错的,年薪30W+,公司挺不错的,也很大但是没去,有点不喜欢这家公司的文化,加班比较严重,离家也非常远,万一家里有点啥事回趟家都费劲.从深圳回个家就小1000没了,来回2000没了…想想就不能接受.
北京也很不错,Offer有游戏开发的岗位,也有传统软件的岗位等,北京真的不太想去了,因为大四在北京广联达总部实习了一年,北京给我的感觉就是堵,走到哪都是排队,排队,再排队.
各种原因就选择了上海,就在选择了上海的Offer之后.突然招聘软件有位好老板联系到了我,问我想不想试试他们的这个岗位. 当时我已经跟上海的另一家公司谈好了,公司也有几百人.我就各种推辞,不太想尝试,有一点是因为公司比较小,觉得可能也没这么可靠吧.而且我之前面试都是Java,这家公司需要C或C++知识体系的人.而且是属于Linux下的C/C++软件开发…
我对Linux情有独钟,因为我从高一就接触到了Linux,高中还参加Linux比赛,拿到了全国的金牌奖项,一直到大学一直在无间断的使用Linux.
其实没看到这家公司招聘之前,我一直不想去找Linux相关的工作,第一是因为感觉运维太简单了,不想接触.第二是难的岗位太难了,而且自己从来没接触过.
后来经过交谈, 这家公司真的给我眼前一亮,好老板说我没接触过这个相关的也没关系,也原因给我时间工作后去学习,而且薪资也可以按照已经找到的工作的薪资付给我.(有点心动了)就答应了可以参加面试.
后来公司的技术负责人和好老板一块参与了交谈和面试, 经过交谈,给我的感觉是这个技术负责人和我大四实习是的师傅一样,人还不错,实习时找的工作就是因为面试的感觉比较好,交谈的比较舒服才决定去这家公司的.而且你不理解的东西,能给你讲的透透的…这妥妥的是一位大佬,有大佬带谁不心动…最后答应就去了这家公司.
就这样,从Java转到C/C++就靠了一个缘分.真的很感谢好老板给的机会.我是真的喜欢Linux.就想挑战有难度的工作.
就这样,到了现在,一直在做Linux嵌入式应用程序,音视频相关的工作,也接触一些Linux内核,驱动相关的工作.都是C/C++.
我认为难点在于(站在嵌入式的领域来说):
下面是我之前记录的一些问题,学习记录而来,还未来得及发博客.正好可以体现出来C++规范.将从以下几个方面来阐述在C与语言开发中所遇到的问题,以及如何使用C++来解决,以及相应的解决方案;
例如,定义了如下4个变量
char c1 = 'yes';
char c2 = "yes";
const char* s1 = "/";
const char* s2 = '/';
可以以你的经验来选择哪个对,哪个错;
答案是:
c1和s1对,c2和s2错;
这里需要注意的是char和char*,双" "引号和单’ '号的区别:
char存放单个字符; char*存放一串字符;
双引号" "存放一个字符串; 但引号’ '存放一个字符;
所以:
我们用char来存放一个字符串是错的
char c2 = "yes";
所以:
用char*存放一个字符是错的
const char* s2 = '/';
你是不是在想:把c2=“yes”,改成c2=“y”,双引号""中只存放单个字符是不是就可以了呢?
char c2 = "yes";
#改成
char c2 = "y";
答案是不可以的;
例如:
char c2 = "y"; // “y” 双引号其实是由\0结尾的,所以真正的存储方式是: {'y','\0'}
有些同志可能对c1有点疑惑,单引号’'不是来存储单个字符的吗?为什么c1=‘yes’,写了3个字符也没问题呢? 这是因为C语言编译器有截断机制;
char c1 = 'yes';//会被截断,结果可能有2种:1.保留首字符,2.保留尾字符
cout << c1 << endl;
如果把c1打印出来,我电脑中的结果是s;
不同的编译器可能结果是不同的。
ubuntu x86的电脑上:
(base) zhenghui@zh-pc:/data/project/CLionProjects/C_Project$ g++ main.cpp
main.cpp:15:15: warning: multi-character character constant [-Wmultichar]
15 | char c1 = 'yes';
| ^~~~~
main.cpp: In function ‘int main()’:
main.cpp:15:15: warning: overflow in conversion from ‘int’ to ‘char’ changes value from ‘7955827’ to ‘'s'’ [-Woverflow]
(base) zhenghui@zh-pc:/data/project/CLionProjects/C_Project$
arm交叉编译工具:
(base) zhenghui@zh-pc:~/tftpboot$ arm-linux-gnueabihf-sigmastar-9.1.0-g++ test.cpp -o test
test.cpp:5:15: 警告: 多字节字符常量 [-Wmultichar]
5 | char c1 = 'yes';
| ^~~~~
test.cpp: 在函数‘int main()’中:
test.cpp:5:15: 警告: unsigned conversion from ‘int’ to ‘char’ changes value from ‘7955827’ to ‘'s'’ [-Woverflow]
(base) zhenghui@zh-pc:~/tftpboot$
可以看到提示的警告信息,会自动转换成s;
又换了一种arm交叉编译工具:
(base) zhenghui@zh-pc:~/tftpboot$ arm-linux-gnueabihf-g++ test.cpp -o test
test.cpp:5:15: 警告: 多字节字符常量 [-Wmultichar]
char c1 = 'yes';
^~~~~
test.cpp: 在函数‘int main()’中:
test.cpp:5:15: 警告: large integer implicitly truncated to unsigned type [-Woverflow]
(base) zhenghui@zh-pc:~/tftpboot$
依然会被截断,结果还是s;
又换了一个,结果还是一样:
zh@xxx:project$ arm-none-linux-gnueabi-g++ test.cpp -o testa
test.cpp:5:15: warning: multi-character character constant
test.cpp: In function 'int main()':
test.cpp:5: warning: large integer implicitly truncated to unsigned type
zh@xxx:project$
对于s1和s2也是:因为char*接收的是一个字符串,但是s2传递的是一个单引号’'的值,所以s2会报错。
const char* s1 = "/";
const char* s2 = '/';
但是char*可以引用char:
char c1 = 'yes'; //s
// char c2 = "yes";
cout << c1 << endl;
const char* s1 = "/";
// const char* s2 = '/';
const char* s2 = &c1; //s
cout << *s2 << endl;
C语言是高级语言中的低级语言。
优点是:小巧,高效,接近地层; 缺点是:细节和陷阱比较多。
使用C++来解决和规避以上问题
C++定义了string类,专门用来存储和提供了一系列的字符串操作。
#include "string"
using namespace std;
string str1(1,'yes');
cout << str1 << endl; // s
string str2(2,'yes');
cout << str2 << endl; // ss
string str3("yes");
cout << str3 << endl; // yes
例如下面这个,传入了1,‘yes’,打印出来就取了1个s
string str1(1,'yes');
cout << str1 << endl; // s
传递2的时候,就打印了2个ss
string str2(2,'yes');
cout << str2 << endl; // ss
就可以规避上面的问题,用C++操作字符串也比较安心。
我们在C语言项目开发中,经常遇到函数之前传递数组的情况,也带来了一些问题。
例如我们有如下一个数组:
int array1[] = {1,2,3,4,5,6,7,8,9,10};
我们求平均值:
double result;
for (int i = 0; i < 10; ++i) {
result += array1[i];
}
result = result / 10;
cout << result << endl; //5.5
如果我们想再填入一些数呢?
int array1[] = {1,2,3,4,5,6,7,8,9,10,123,531,2,5,6,7,8,9,1233,54,123,64,257,98};
估计自己数都数晕了吧。
在C语言中可以使用sizeof()函数计算一个数组的长度。
例如我们可以改成这样:
int array1[] = {1,2,3,4,5,6,7,8,9,10,123,531,2,5,6,7,8,9,1233,54,123,64,257,98};
int len = sizeof(array1) / sizeof(array1[0]);
double result;
for (int i = 0; i < len; ++i) {
result += array1[i];
}
result = result / len;
cout << result << endl;
有了自动计算数组中元素个数的代码,我们就不用再手动计算了。
但是我们把计算平均值的代码提出为一个独立函数时该怎么做呢?
可以写一个函数,把数组传递过去,然后返回平均值
double avg1(int array[]) {
int len = sizeof(array) / sizeof(array[0]);
double result;
for (int i = 0; i < len; ++i) {
result += array[i];
}
result = result / len;
return result;
}
int main() {
int array1[] = {1,2,3,4,5,6,7,8,9,10,123,531,2,5,6,7,8,9,1233,54,123,64,257,98};
int len = sizeof(array1) / sizeof(array1[0]);
cout << avg1(array1) << endl;
return 0;
}
运行结果:
真是现实比较骨感阿。
1.5
算出来的值是不对的。
为什么造成这个结果呢?
我们在2个函数中打印以下len的长度看看:
double avg1(int array[]) {
int len = sizeof(array) / sizeof(array[0]);
cout << "avg1 len->" << len << endl; //2
double result;
for (int i = 0; i < len; ++i) {
result += array[i];
}
result = result / len;
return result;
}
int main() {
int array1[] = {1,2,3,4,5,6,7,8,9,10,123,531,2,5,6,7,8,9,1233,54,123,64,257,98};
int len = sizeof(array1) / sizeof(array1[0]);
cout << "main len->" << len << endl; //24
cout << avg1(array1) << endl;
return 0;
}
运行结果:
main len->24
avg1 len->2
1.5
为什么传递过去的数组没能计算出来结果呢?
因为:
在C语言中传递数组时,编译器会把数组[]转换成指针的方式传递过去;所以sizeof计算出来的结果并不是正确的。
编译的时候,也会warning:
(base) zhenghui@zh-pc:/data/project/CLionProjects/C_Project$ g++ main.cpp
main.cpp: In function ‘double avg1(int*)’:
main.cpp:8:22: warning: ‘sizeof’ on array function parameter ‘array’ will return size of ‘int*’ [-Wsizeof-array-argument]
8 | int len = sizeof(array) / sizeof(array[0]);
| ~^~~~~~
main.cpp:7:17: note: declared here
7 | double avg1(int array[]) {
| ~~~~^~~~~~~
(base) zhenghui@zh-pc:/data/project/CLionProjects/C_Project$
copy一份avg1改写avg2:
这次改写成指针的方式来接收一个数组,看看计算的结果是不是一样
double avg2(int *array) {
int len = sizeof(array) / sizeof(array[0]);
cout << "avg2 len->" << len << endl; //2
double result;
for (int i = 0; i < len; ++i) {
result += array[i];
}
result = result / len;
return result;
}
int main() {
int array1[] = {1,2,3,4,5,6,7,8,9,10,123,531,2,5,6,7,8,9,1233,54,123,64,257,98};
int len = sizeof(array1) / sizeof(array1[0]);
cout << "main len->" << len << endl; //24
cout << "avg1:"<< avg1(array1) << endl;
cout << "avg2:"<< avg2(array1) << endl;
return 0;
}
运行结果:
avg2(int *array) 和 avg1(int array[]) 运行的结果是一样的,说明数组确实是被转成指针了
main len->24
avg1:avg1 len->2
1.5
avg2:avg2 len->2
1.5
值得一提的是,我们手动g++编译的时候,avg2并没有报出warning信息,说明我们用指针的方式来接收一个数组的语法是正确的,编译器是认可的。
C语言中如何解决数组传递计算的值的多少不对的问题呢?
答案是在传递数组的时候把数组中的元素个数提前计算好,一起传递过去。
我们利用avg2改写avg3:
double avg3(int *array, int len) {
cout << "avg3 len->" << len << endl; //2
double result;
for (int i = 0; i < len; ++i) {
result += array[i];
}
result = result / len;
return result;
}
int main() {
int array1[] = {1,2,3,4,5,6,7,8,9,10,123,531,2,5,6,7,8,9,1233,54,123,64,257,98};
int len = sizeof(array1) / sizeof(array1[0]);
cout << "main len->" << len << endl; //24
cout << "avg1:"<< avg1(array1) << endl; //1.5
cout << "avg2:"<< avg2(array1) << endl; //1.5
cout << "avg3:"<< avg3(array1, len) << endl; //107.292
return 0;
}
再次运行结果:
可以看到正确了。
main len->24
avg1:avg1 len->2
1.5
avg2:avg2 len->2
1.5
avg3:avg3 len->24
107.292
用C++解决上述问题
在C++中提供了vector对象,需要include一下:
#include "vector"
copy avg3改写avg4:
double avg4(vector<int> v) {
cout << "avg4 len->" << v.size() << endl;
double result;
for (int i = 0; i < v.size(); ++i) {
result += v[i];
}
result = result / v.size();
return result;
}
vector数组的初始化如下:
int main() {
int array1[] = {1,2,3,4,5,6,7,8,9,10,123,531,2,5,6,7,8,9,1233,54,123,64,257,98};
int len = sizeof(array1) / sizeof(array1[0]);
cout << "main len->" << len << endl; //24
cout << "avg1:"<< avg1(array1) << endl; //1.5
cout << "avg2:"<< avg2(array1) << endl; //1.5
cout << "avg3:"<< avg3(array1, len) << endl; //107.292
vector<int> v{1,2,3,4,5,6,7,8,9,10,123,531,2,5,6,7,8,9,1233,54,123,64,257,98};
cout << "avg4:"<< avg4(v) << endl; //107.292
return 0;
}
运行结果:
main len->24
avg1:avg1 len->2
1.5
avg2:avg2 len->2
1.5
avg3:avg3 len->24
107.292
avg4:avg4 len->24
107.292
比较高效的传递方式是采用引用的方式传递过来:
这样传递参数是比较高效的。
double avg4(vector<int> &v){
...
}
还可以改成迭代器的方式:
double avg5(vector<int> &v) {
cout << "avg4 len->" << v.size() << endl;
double result;
vector<int>::iterator itr = v.begin();
for (; itr != v.end(); ++itr) {
result += (*itr);
}
result = result / v.size();
return result;
}
使用vector写二维数组:
double avg6(vector<vector<int>> &vv) {
double result;
int data_num = 0;
for (int i = 0; i < vv.size(); ++i) {
for (int j = 0; j < vv[i].size(); ++j) {
result += vv[i][j];
data_num++;
}
}
result = result / data_num;
return result;
}
int main() {
vector<vector<int>> vv{{1,2,3},{1,2,3},{1,2,3}};
cout << "avg6:"<< avg6(vv) << endl;
return 0;
}