C和C++常见误区以及问题整理

c和c++的关系

c是面向过程的语言,c++是在c的基础上扩展的面向对象的编程语言。
c++具备c的所有功能,对c的库完全兼容。
c++的标准在98年确定,在那之前已经有一些库大量使用。
新标准中,推出了名称空间的概念,既是为了方便人们使用新标准的同时,不用大量修改之前的代码,对之前的代码兼容,同时可以有效的避免名称冲突。
旧标准中以.h结尾
新标准没有.h
旧标准中可以直接包含c的库文件,编译器会附带c的兼容库实现
新标准中有一样的c库子模块支持,命名方式变更为:原stdio.h,新cstdio,即前面+c,后面去掉.h

C++标准库(C++ Standard Library),是类库和函数的集合。 
C++编译器厂商根据C++标准委员会官方的ISO规范并将其转化为代码。
C++编译器厂商在实现C++标准库过程中必须依赖其不同操作系统所提供的系统调用接口,因此每个平台都有其自己的C++标准库实现。
C++标准库的特点如下:
A、C++标准库不是C++语言标准的一部分,由类库和函数库组成。
B、C++标准库中定义的类和对象都位于std命名空间中。
C、C++标准库的头文件都不带.h后缀。
D、C++标准库涵盖了C库的功能
E、C++标准库中包含一个涵盖C库功能的子库,通常头文件以c开头,如#include <cmath>#include <cstring>等。

如何理解名称空间

命名空间存在的目的是为了解决源代码中的重名问题。比如你写代码的时候需要用到矩阵计算,于是你定义了一个类,叫做Matrix。然后你引入的第三方库中,也有一个叫做Matrix的类,于是乎就重名了。为了解决这个问题,只需要把它们放在不同的命名空间里,比如你的叫做foo::Matrix, 第三方库的叫做third_party::Matrix,这样它们就有了不同的名字,编译器就可以正确识别出你在代码中用的Matrix是哪一个。

这个时候如果你同时使用了using namespace foo,using namespace third_party,就又会使这两个不同的类具有相同的标识符。因此在良好的编程风格中,尽可能的避免使用using namespace,或者仅在翻译单元(可以理解为是一个cpp文件)内、函数内、类内使用(using具体的对象、函数)。

第二个问题是是不是所有的程序名字都要在std中。恰恰相反,C++标准禁止用户自己扩充std命名空间,所以用户的代码应该是处于非std空间中,例如默认命名空间:: 。但是,事实上每一个编译器都支持用户在std空间中定义自己的类、函数、对象,因此在std实现自定义类的哈希函数也是可以编译通过的,尽管这是一个违背标准的行为。

在刷算法时,可以随意一点,按照这种方式使用

using namespace std; // avoid as too indiscriminate(随意)

严谨一点可以这样,最大限度地避免冲突的产生

using std::cin;
using std::cout;
using std::endl;
int x;
cin >> x;
cout << x << endl;

或者这样

int x;
std::cin >> x ;
std::cout << x << std::endl;

However,

using namespace std;

is considered a bad practice because you are practically importing the whole standard namespace, thus opening up a lot of possibilities for name clashes. It is better to import only the stuff you are actually using in your code, like

using std::string;

字符串类型

C语言不支持真正意义上的字符串,但可以使用字符数组和一组函数实现字符串操作。C语言不支持自定义类型,因此也不能定义字符串类型。

C++语言可以自定义类型,可以通过类完成字符串类型的定义,但C++语言也没有原生的字符串类型。C++语言通过C++标准库提供的string类型实现对字符串类型的支持。string类的特性如下:
A、string直接支持字符串连接
B、string直接支持字符串的大小比较
C、string直接支持子串查找和提取
D、string直接支持字符串的插入和替换

变量声明与定义

extern int i; //声明,不是定义
int i; //声明,也是定义
定义只能出现在一处。也就是说,不管是 int a 还是 int a=0 都只能出现一次,而 extern int a 可以出现很多次。
当你要引用一个全局变量的时候,你就要声明 extern int a 这时候 extern 不能省略,因为省略了,就变成 int a 这是一个定义,不是声明。

前缀指定基数:

  • 0x 或 0X 表示十六进制,
  • 0 表示八进制,
  • 0b表示二进制
  • 不带前缀则默认表示十进制

后缀是 U 和 L 的组合,U 表示无符号整数(unsigned),L 表示长整数(long)。后缀可以是大写,也可以是小写,U 和 L 的顺序任意。

结构数据类型

结构数据类型允许构造由多个基础数据类型组合而成的复杂结构,结构数据类型为面向对象的蓝本。以下的结构数据类型通过指针实现了二叉树结构

typedef struct Bintree {
    int data;
    struct bintree *lchild; // left child of the node
    struct bintree *rchild; // right child of the node
} bintree; // 自定义 bintree 类型

&&,||,&,|

&&:逻辑与,前后条件同时满足表达式为真
||:逻辑或,前后条件只要有一个满足表达式为真
&:按位与
|:按位或
&&和||是逻辑运算,&与|是位运算

*,&
*的作用
1.乘号(Multiply)
2.声明指针(Pointer Statement)

//就是声明变量a是5,把a的地址附到指针ptr上
int a =5; int* ptr=&a;

3.解引用 (Dereference)

*ptr 单独拿出来就是找出 ptr指针指向的值,按照第二点的说法就是5

&的作用

&叫做取地址符号
一般指针只能接受一个内存地址而不能接受一个值

//错误表达,指针不能接受一个值
int a =5; int* ptr=a;

//正确表达,把a的地址给指针ptr
int a =5; int* ptr=&a;

案例:

数据结构伪代码理解
比如定义链表时:
typedef struct Node{

}Node,*Linklist;

在创建函数时候这样,
int creatlist(Linklist &L){}

用这个函数时候需要这样写
creatlist(L);

而定义顺序表时
typedef struct{
}List;

创建函数时候
int creatlist(List *l){}

用函数的时候
creatlist(&l);

解答

不关引用和题主C语言不好的事,事情应该是这样的:
并不是你的教材和你的老师讲错了,这样的代码是有意为之。但是程序又跑不起来,那问题出在哪呢。问题就在于大多数数据结构教材一开始就告诉了你,
本书的算法都是用类C语言伪码实现的,并非是严格意义上的C语言。在创建函数时候这样,

int creatlist(Linklist &L){}

用这个函数时候需要这样写creatlist(L);

为什么这么创建(定义)函数呢?因为编书人想告诉你的是函数的参数并非变量本身,而是存放变量的地址(有些答主学了C++,看到&就是引用,真的,你太敏感了)。
为什么要这么调用呢?因为函数的定义,函数调用需要传一个地址进去,那么传一个指针进去是理所当然的。再来看这段代码。而定义顺序表时
typedef struct{
}List;

创建函数时候
int creatlist(List *l){}

用函数的时候
creatlist(&l);

WTF?看起来跟上面的定义和调用格式都完全不一样哎,又懵逼了...其实是这样的:为什么这样创建(定义)函数呢?和上其实同理,如果这样写,typedef struct{
}List;

int creatlist(List l){}就是在说你只是传了一个结构体进去。所以作者加个*,是想告诉你这里传进去的是个顺序表。
为什么这么调用呢?还是因为定义,函数需要一个地址,那么我们就传一个地址进去。综上所述,这几段代码肯定是跑不起来的,因为根本不是C语言代码,只是伪代码而已,那作者是吃多了才这么写么?不是。作者只是想简化用来实现算法的语言,因为数据结构中选用的语言根本不是重点,重点是各种数据结构的思想。换句话说作者没想让你把程序跑起来,作者只是想让你能更容易懂。说到这里我想你应该很明白了,程序跑不起来书和老师都没有错(也不是某些答主说的C++中的引用或者你的C语言学得不好),既然作者已经将语法简化得不能再简化了,何妨不将教材上的伪代码充分理解,然后选取一门语言自己实现它呢?或许作者选用伪代码来讲述也有这一层原因(逼你自己动手)吧。

参考链接:请问 C 语言中 & 和 * 的用法? - 陈思定的回答 - 知乎

gcc,g++,gdb,cc

gcc and g++ are compiler-drivers of the GNU Compiler Collection (which was once upon a time just the GNU C Compiler).Even though they automatically determine which backends (cc1 cc1plus ...) to call depending on the file-type, unless overridden with -x language, they have some differences.The probably most important difference in their defaults is which libraries they link against automatically.According to GCC's online documentation link options and how g++ is invoked, g++ is equivalent to gcc -xc++ -lstdc++ -shared-libgcc (the 1st is a compiler option, the 2nd two are linker options). This can be checked by running both with the -v option (it displays the backend toolchain commands being run).

  • GCC: GNU Compiler Collection
    • Referrers to all the different languages that are supported by the GNU compiler.
  • gcc: GNU C      Compiler
  • g++: GNU C++ Compiler

The main differences:

  • gcc will compile: *.c , *.cpp files as C and C++ respectively.
  • g++ will compile: *.c , *.cpp files but they will all be treated as C++ files.
  • Also if you use g++ to link the object files it automatically links in the std C++ libraries (gcc does not do this).
  • gcc compiling C files has fewer predefined macros(预定义宏命令).
  • gcc compiling *.cpp and g++ compiling *.c/*.cpp files has a few extra macros.

reference link

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值