c++面试知识点,全面认识c++(持续更新,欢迎留言)

目录

一、关于c++

 二、c++编程

1. C++的基本数据类型有哪些?

(1). 整数类型(int, long 以及 short)

(2). 浮点数类型(float 和 double)

(3). 字符类型(char)

(4). 布尔类型(bool)

(5). 空类型(void)

2. C++中的引用是什么?

 3. C++中的指针是什么?

(1). 使用指针作为函数参数

(2). 动态分配内存

(3). 数组

(4). 使用指针处理字符串

4.指针和引用的区别是什么?

5. C++中的const关键字是什么?

(1). 修饰变量,创建一个只读变量(常量):

(2). 修饰函数返回类型,指示该函数不会修改其返回值:

(3). 修饰函数参数,在函数内部保护参数值不被修改:

6. C++中的类是什么? 什么是面向对象编程?请举例

7. C++中的继承是什么? 

(1). 公有继承

(2). 私有继承

(3). 保护继承

8. C++中的多态是什么? 

9. 解释 RAII 的概念。

10. 解释 C++ 11 中的移动语义。

 11.c++中delete和delete[]的区别

 12.c++的多线程编程

线程的生命周期?

13.编译的四个步骤

 三、c++环境

1.Makefile

(1)CMake

(2)手写Makefile

2.c++添加库(非内置)

(1)g++

(2)Dev c++


一、关于c++

C++ 是一种面向对象的编程语言,它是 C 语言的扩展,具有更强大的功能和更高的抽象级别。以下是 C++ 的一些重点:

  • 1. 面向对象编程:C++ 是一种面向对象的编程语言,它支持封装、继承和多态等面向对象的特性。
  • 2. 泛型编程:C++ 支持泛型编程,可以使用模板来编写通用的代码,提高代码的复用性和可维护性。
  • 3. 内存管理:C++ 中需要手动管理内存,包括内存的分配和释放,需要注意内存泄漏和野指针等问题。
  • 4. 异常处理:C++ 支持异常处理,可以在程序出现异常时抛出异常并进行处理,提高程序的健壮性。
  • 5. 标准库:C++ 标准库提供了丰富的函数和类,包括输入输出、容器、算法、字符串处理等,可以大大提高程序的开发效率。
  • 6. 多线程编程:C++11 引入了多线程编程的支持,可以使用 std::thread 类来创建和管理线程,提高程序的并发性能。
  • 7. STL:STL(Standard Template Library)是 C++ 标准库中的一个重要组成部分,提供了容器、迭代器和算法等模板类和函数,可以大大提高程序的开发效率和代码的可读性。
  • 8. 智能指针:C++11 引入了智能指针的概念,可以自动管理内存,避免了手动管理内存的繁琐和错误。

 二、c++编程

1. C++的基本数据类型有哪些?

        C++ 中的基本数据类型是指不同类型的变量、值和对象,其数据在计算机中以二进制形式存储,并且可以直接使用内置运算符对其进行操作。以下是 C++ 中主要的基本数据类型:

(1). 整数类型(int, long 以及 short)

        整数类型用于表示整数值,包括正数、负数和零。其中,int 表示一个整数,通常为 4 字节大小,long 也表示整数,但是其长度通常大于 int ,long 可能为 8 字节大小,short 表示一个短整数,通常为 2 字节大小。这些类型都有无符号版本(unsigned)。

(2). 浮点数类型(float 和 double)

        浮点数类型用于表示小数值,包括单精度浮点数和双精度浮点数。其中,float 表示单精度浮点数,占用 4 字节空间,而 double 表示双精度浮点数,占用 8 字节空间。这些类型的值用科学计数法表示,即用一个小数表示一段数学常量与一个指数乘积的表达式。

(3). 字符类型(char)

        字符类型用于表示单个字符,如字母、数字和标点符号等。char 类型通常占用 1 字节,取值范围-128~127(有被考过哈哈哈),有无符号版本(unsigned char)。

(4). 布尔类型(bool)

        布尔类型用于表示逻辑量,只有两个值:true 和 false。通常占用 1 字节。

(5). 空类型(void)

        空类型不表示任何值,但通常用于作为函数的返回类型或者指针的类型。

此外,C++ 还支持宽字符类型(wchar_t)、枚举类型(enum)和 C 风格字符串类型。可以通过组合这些基本数据类型来创建结构体、联合体等复合数据类型。

2. C++中的引用是什么?

        引用是C++中的一种数据类型,它是一个别名,用于引用另一个变量。引用可以看作是一个变量的别名,对引用的操作实际上就是对原变量的操作。引用的定义方式为:类型 &引用名 = 原变量名;

以下是一些引用的示例:

```
int main() {
    int x = 10;
    int &y = x; // y 是 x 的引用
    cout << "x is: " << x << endl; // 输出 "x is: 10"
    cout << "y is: " << y << endl; // 输出 "y is: 10"

    y++; // 修改 y 的值同样会修改 x 的值
    cout << "x is now: " << x << endl; // 输出 "x is now: 11"

    x++; // 同样可以通过修改 x 的值来改变 y 的值
    cout << "y is now: " << y << endl; // 输出 "y is now: 12"

    return 0;
}
```

上述程序展示了如何创建引用 y,使其成为变量 x 的别名,并且对任意一个变量的修改都会影响到另一个变量。

引用还可以用作函数参数,从而使得函数能够更直接地操作实际的变量。例如:

```
void swap(int &a, int &b) { // a 和 b 都是整数的引用
    int temp = a;
    a = b;
    b = temp;
}

int main() {
    int x = 10, y = 20;
    swap(x, y); // 直接交换 x 和 y 的值
    cout << "x is now: " << x << endl; // 输出 "x is now: 20"
    cout << "y is now: " << y << endl; // 输出 "y is now: 10"

    return 0;
}
```

在上述程序中,swap() 函数使用引用参数来直接访问 x 和 y 的值,并有效地交换它们。

 3. C++中的指针是什么?

        指针是C++中的一种数据类型,它存储了一个变量的地址。指针可以用来访问和修改变量的值,也可以用来动态分配内存。指针的定义方式为:类型 *指针名 = &变量名;

        C++ 中的指针是一种非常有用的语言特性,可以在代码中引入更高级别的抽象和控制结构。以下是一些例子,涵盖了指针的不同应用场景:

(1). 使用指针作为函数参数

         C++中我们可以传递指针类型的参数给一个函数,从而使得函数能够修改指针所指向的值,这个特性被称为指针传递。例如:

```
void changeValue(int *p) { //将一个指向整数的指针作为函数参数
    *p = 5; //更改指针所指向内存位置上的值
}

int main() {
    int x = 10;
    changeValue(&x);
    cout << "x 现在是: " << x << endl; //输出“x现在是:5”
    return 0;
}
```

(2). 动态分配内存

        在 C++ 中,我们可以使用 new 运算符动态地分配内存,然后将结果存储在指针变量中。这使得我们可以轻松地创建可重新调整大小的数组以及其他动态分配的数据结构。例如:

```
int *p = new int(42); // 分配一个 int 并初始化为 42
float *f = new float[100]; // 分配一个包含100个浮点数的数组

// 在使用完之后必须使用 delete 和 delete[] 进行正确的清理:
delete p;
delete[] f;
```

(3). 数组

        指针与数组密切相关。数组名是指向其第一个元素的指针,可以通过对它进行算术操作来遍历整个数组。例如:

```
int arr[5] = { 1, 2, 3, 4, 5 };
int *p = arr; //把指针 p 指向 arr 的第一个元素
for (int i = 0; i < 5; i++) {
    cout << *(p + i) << " "; // 输出 1 2 3 4 5
}
cout << endl;
```

(4). 使用指针处理字符串

        字符串在 C++ 中通常被视为 char 型数组。我们可以使用指针来访问和操作这些字符。例如:

`

``
char greeting[] = "Hello, world!";
char *p = greeting; // 将指针设置为 greeting
while (*p != '\0') { // 遍历直到 null 字符结束
    cout << *p;
    p++; // 将指针移动到下一个字符
}
cout << endl; // 输出“Hello, world!”
```

指针还有许多其他应用场景,例如链表、树、图形等高级数据结构的实现,以及编写底层代码时使用指针来优化内存管理和函数调用。了解这些应用程序需要更深入的知识和经验。

4.指针和引用的区别是什么?

1. 语法上的区别:指针使用 * 符号来声明和间接访问内存地址,而引用使用 & 符号来声明和直接访问变量,不需要间接操作符。

2. 操作上的区别:指针可以被赋值为 nullptr 或者其他地址,也可以被重新赋值,而引用必须在创建时就初始化,并且无法改变其引用的对象。

3. 内存上的区别:指针是一个独立的变量,它有自己的内存地址,而引用则是被引用变量的别名,没有自己的内存地址。

4. 安全性上的区别:引用相对于指针更加安全,因为它只能引用已经存在的对象,而指针可能会指向未分配或已释放的内存空间。

下面是一个简单的例子,展示了引用和指针的区别:

```
#include <iostream>
using namespace std;

int main() {
    int a = 10;
    int* p = &a; // 指针p指向a
    int& r = a;  // 引用r引用a

    cout << "a = " << a << endl;
    cout << "*p = " << *p << endl;
    cout << "r = " << r << endl;

    *p = 20; // 改变指针p所指向的值
    r = 30;  // 改变引用r所引用的值

    cout << "a = " << a << endl;
    cout << "*p = " << *p << endl;
    cout << "r = " << r << endl;

    return 0;
}
```

输出结果为:

```
a = 10
*p = 10
r = 10
a = 30
*p = 30
r = 30
```

可以看到,指针和引用都可以用来修改变量的值,但是指针需要通过间接操作符 * 访问它所指向的内存地址,而引用直接访问被引用的变量。另外,当改变指针或引用所指向的对象时,它们所引用的变量的值也会相应地发生改变。

5. C++中的const关键字是什么?

        在 C++ 中,const 关键字用于修饰变量、函数返回类型、函数参数等以防止它们被修改。使用 const 关键字定义的变量称为常量,一旦赋值之后就不能再改变它们的值。

以下是几个 const 的使用示例:

(1). 修饰变量,创建一个只读变量(常量):

```
const int MaxValue = 100;
// 在程序中只能读取该常量,不能修改
int x = MaxValue + 10; // 正确
MaxValue += 10; // 编译错误:MaxValue 是只读常量
```

(2). 修饰函数返回类型,指示该函数不会修改其返回值:

```
const int getRandomNumber() {
    return rand(); // 返回一个随机数,但不会修改任何状态
}int main() {
    int num = getRandomNumber(); // OK
    getRandomNumber() = 42; // 编译错误:getRandomNumber() 的结果是只读
}
```


(3). 修饰函数参数,在函数内部保护参数值不被修改:

```
void print(const std::string& message) {
    // 不能修改参数 message
    std::cout << message << std::endl;
}

int main() {
    std::string myMessage = "Hello World!";
    print(myMessage); // OK
    myMessage[0] = 'h'; // 错误,试图修改参数值
    print(myMessage); // 依然输出 "Hello World!"
}
```

总而言之,const 关键字可以帮助我们保护代码中的数据,防止无意中对其进行修改或破坏,从而提高程序的健壮性和可读性。

6. C++中的类是什么? 什么是面向对象编程?请举例

        在 C++ 中,类是对具有相似特征(数据成员)和行为(成员函数)的对象进行抽象的方式。它们可以用于组织代码、封装数据结构和实现抽象数据类型。

        面向对象编程(Object-Oriented Programming, OOP)是一种编程方法,它通过定义类和实例化对象来模拟真实世界中的事物,并利用对象之间的交互来实现计算机程序。OOP 的主要思想是“万物皆可对象”,即将问题分解为对象和对象之间的交互,强调数据封装、继承和多态等概念,以实现高内聚、低耦合的程序设计。

以下是一个简单的 C++ 类的示例:

```
class Point {
public:
    // 构造函数,初始化对象
    Point(int xCoord, int yCoord) : x(xCoord), y(yCoord) {}

    // 访问器函数
    int getX() const { return x; }
    int getY() const { return y; }

    // 修改器函数
    void setX(const int newX) { x = newX; }
    void setY(const int newY) { y = newY; }

    // 成员函数,计算点到原点的距离
    double distanceToOrigin() const {
        return std::sqrt(x*x + y*y);
    }

private:
    int x;  // 横坐标
    int y;  // 纵坐标
};
```

在上面的示例中,Point 类表示平面上一个点的坐标。它具有两个属性(横纵坐标)和一些方法(访问器、修改器和计算距离到原点的函数)。这个类可以用于实例化无数个具体的点对象,并进行各种操作。

例如:

```
int main() {
    Point p1(2, 3);
    Point p2(-4, 1);

    // 使用访问器函数读取 x 和 y 坐标
    std::cout << "p1: (" << p1.getX() << ", " << p1.getY() << ")" << std::endl;
    std::cout << "p2: (" << p2.getX() << ", " << p2.getY() << ")" << std::endl;

    // 调用成员函数计算距离
    std::cout << "Distance from p1 to origin: " << p1.distanceToOrigin() << std::endl;
    std::cout << "Distance from p2 to origin: " << p2.distanceToOrigin() << std::endl;

    // 使用修改器函数修改坐标
    p1.setX(5);
    p2.setY(0);
}
```

在主函数中,我们创建了两个具体的点对象 p1 和 p2,并通过调用类的方法来运用利用这两个对象完成一些任务。

7. C++中的继承是什么? 

         继承是C++中的一种面向对象编程的特性,它允许一个类继承另一个类的属性和行为。继承的类称为派生类,被继承的类称为基类。派生类可以访问基类的公有成员和保护成员,但不能访问基类的私有成员。继承的方式有公有继承、私有继承和保护继承三种。

在 C++ 中,继承是一种使一个类从另一个类获取特性和行为的机制。C++ 支持三种访问控制标识符:public、private 和 protected 来限制派生类对基类成员的访问权限。以下是这些继承方式的解释和示例:

(1). 公有继承

公有继承将基类中的所有公共成员都转移到了派生类中,并使得这些成员仍然可以被外部代码访问。例如:

```
class Animal {
public:
    void eat() { cout << "Animal is eating!" << endl; }
};

class Cat : public Animal { //公共继承自 Animal
public:
    void meow() { cout << "Cat is meowing!" << endl; }
};

int main() {
    Cat myCat;
    myCat.eat(); //输出“Animal is eating!”
    myCat.meow(); //输出“Cat is meowing!”
    return 0;
}
```

上述程序显示了 Cat 类使用公有继承从 Animal 类获得 eat() 函数的能力。

(2). 私有继承

私有继承是指基类中的公共成员不被传递到派生类中。这意味着只有派生类自己才能使用被继承类的成员,而基类成员对外部不可见。例如:

```
class FlyingAnimal {
public:
    void fly() { cout << "Flying animal is flying!" << endl; }
};

class Bird : private FlyingAnimal { //私有继承自 FlyingAnimal
public:
    void tweet() { cout << "Bird is tweeting!" << endl; }
    void flyBird() {
        fly(); //从 FlyingAnimal 类继承的函数
    }
};

int main() {
    Bird myBird;
    myBird.tweet(); //输出“Bird is tweeting!”
    myBird.flyBird(); //输出“Flying animal is flying!”
    return 0;
}
```

上述程序中,Bird 类使用私有继承从 FlyingAnimal 类获得了 fly() 函数的能力。但是,派生类不允许在其代码之外显示任何基类成员。

(3). 保护继承

保护继承是介于公共和私有继承之间的形式,它允许派生类使用被继承类的成员,但将这些成员标记为受保护,并防止外部访问。例如:

```
class LivingThing {
protected:
    void breathe() { cout << "Object is breathing!" << endl; }
};

class Person : protected LivingThing { //受保护的继承自 LivingThing
public:
    void talk() {
        breathe(); //从 LivingThing 类继承的函数
        cout << "Person is talking!" << endl;
    }
};

int main() {
    Person me;
    me.talk(); //输出“Object is breathing!”和“Person is talking!”
    return 0;
}
```

上述程序表明了 Person 类使用保护继承从 LivingThing 类获得 breathe() 函数的能力,并将其用作 talk() 函数的内部实现。LivingThing 成员不能从 Person 实例对象之外访问或调用。

8. C++中的多态是什么? 

        多态是C++中的一种面向对象编程的特性,它允许不同的对象对同一消息做出不同的响应。多态有两种实现方式:虚函数和模板。虚函数是在基类中定义的虚函数,在派生类中可以重写该函数,实现不同的行为。模板是一种通用的函数或类,可以用于处理不同类型的数据。 

         在继承关系中,子类对象可以替代基类对象,而调用的方法却根据不同的子类返回不同的结果。例如:

```
class Animal {
public:
    virtual void makeSound() { cout << "无声动物" << endl; }
};

class Cat : public Animal {
public:
    void makeSound() { cout << "喵喵叫" << endl; }
};

class Dog : public Animal {
public:
    void makeSound() { cout << "汪汪叫" << endl; }
};

int main() {
    Animal *a;
    Cat c;
    Dog d;
    a = &c;
    a->makeSound(); // 将输出“喵喵叫”
    a = &d;
    a->makeSound(); // 将输出“汪汪叫”
    return 0;
}
```

9. 解释 RAII 的概念。

        RAII (Resource Acquisition Is Initialization)是一种使用 C++ 对象管理资源分配和释放的方法。其核心思想是,在创建对象时获取资源,在对象生命周期结束时释放这些资源,将资源管理代码封装在对象中。RAII 可以确保每个资源得到一个明确定义的行为,从而避免资源泄露,提高代码可靠性。例如:

```
class FileHandle {
public:
    FileHandle(const char* filename) { file = fopen(filename, "r"); }
    ~FileHandle() { fclose(file); }
    //...
private:
    FILE *file;
};

void foo() {
    FileHandle fh("myfile.txt");
    //...
    // 在此处使用文件句柄
    //...

} // 当执行程序离开该作用域时,自动释放文件句柄

```

10. 解释 C++ 11 中的移动语义。

        C++ 11 引入了右值引用并支持转移语义,允许将所有权从一个对象转移到另一个对象而不进行任何复制。这就是移动语义。在传统情况下,当我们将一个对象赋给另一个对象时,将复制整个对象。但对于具有移动构造函数和/或移动赋值运算符的对象,可以将其安全地转移到新对象中,而无需进行副本。这可以提高代码性能。例如:

```
#include <iostream>
#include <vector>

using namespace std;

int main() {
    vector<int> v1{ 1, 2, 3 };
    vector<int> v2{ move(v1) }; // 移动v1到v2,释放v1的内存并将所有权转移给v2

    cout << "v1.size() = " << v1.size() << endl; // Size 将输出 0,因为v1不再拥有元素
    cout << "v2.size() = " << v2.size() << endl; // Size 将输出 3

    return 0;
}
```

 11.c++中delete和delete[]的区别

在 C++ 中,delete 和 delete[] 都是用于释放动态分配的内存。它们之间的区别在于:

        - delete 只应该用于释放由 operator new 分配的单个对象;
        - delete[] 应该用于释放指向数组的内存(即由 operator new[] 分配)。

        显然,如果您使用 delete 释放一个数组,或者使用 delete[] 释放单个对象,这可能会导致不可预测的结果,从而使程序出错。

以下是两种语法的示例:

```
int *p = new int(10); // 分配一个整数
delete p;             // 释放该整数

int *arr = new int[10]; // 分配一个整数数组
delete[] arr;           // 释放该数组
```

总之,为避免内存泄漏和其他问题,务必正确地匹配 delete 和 delete[] 与相应的 new 和 new[] 运算符,并始终遵循 RAII 的方法,在合适的时间删除内存。

 12.c++的多线程编程

C++ 中的多线程编程可以使用标准库中提供的 thread 和其他相关类来实现。下面是一个简单的示例,展示了如何创建一个新的线程、并与主线程之间进行交互:

```
#include <iostream>
#include <thread>

void say_hello() {
    std::cout << "Hello, Concurrent World!\n";
}

int main() {
    // 创建一个新的线程,并启动它执行 say_hello 函数
    std::thread t(say_hello);

    // 等待新线程执行完毕
    t.join();

    // 在主线程中输出消息
    std::cout << "Goodbye, Concurrent World!\n";
    return 0;
}
```

        在上述示例中,我们定义了一个函数 say_hello,它代表正在另一个线程中运行的代码。然后,我们通过 std::thread 类来创建一个新线程,并将 say_hello 作为参数传递给它。在主线程中调用 join 函数等待新线程结束,并且输出一条结束消息。

        除了创建和管理线程外,C++ 的多线程编程还包括了同步机制(如 mutex、condition variable 和 atomic),以确保不同线程之间的顺序和数据可见性,从而避免竞态条件和其他问题。另外,C++11 横跨多个线程的内存模型也得到了指定,以保证正确表现跨线程共享数据等操作。

        需要注意的是,多线程编程具有其自身的挑战和风险,例如死锁、竞争条件和数据竞争。正确地编写并发程序需要细致的设计和仔细的测试,清晰的理解所有潜在的线程交互,并采用适当的同步机制保证安全和可靠性。

线程的生命周期?

C++中多线程编程时,线程的生命周期包括以下几个阶段:

1. 创建阶段:在主线程中通过调用 std::thread 类或相关库函数来创建一个新线程。
2. 运行阶段:新线程开始运行并执行自己的代码,直到遇到了 join() 或 detach() 方法。
3. 等待阶段:主线程调用 join() 方法等待子线程完成运行并回收资源,或者使用 detach() 方法将子线程与主线程分离。
4. 结束阶段:子线程运行结束或被强制结束后释放资源,并退出运行。

13.编译的四个步骤

C++编译的过程通常包括以下四个步骤:

1. 预处理(Preprocessing):处理源代码文件,将 #include、#define等预处理指令展开,并去除注释等不必要的内容,生成一个新的临时文件
2. 编译(Compilation):将预处理后的临时文件转化为汇编语言文件(Assembly file),即将高级语言转换为机器能够执行的低级语言。
3. 汇编(Assembly):将汇编语言文件转化为机器码目标文件(Object file)。
4. 链接(Linking):将编译生成的目标文件与所需的库文件(例如标准库)进行链接,生成可执行文件(Executable file)。

在实际情况中,这些步骤可能会有所变化或者合并,例如某些编译器会同时进行编译和汇编操作,但那是工具的事,我们作为开发者一定要知道是这四个步骤,同时在面试的过程中也一定要可以回答。

 三、c++环境

1.Makefile

(1)CMake

CMake 是一种跨平台的、开源的构建工具,它能够自动生成 Makefile 或 Visual Studio 的解决方案,以便开发人员更轻松地编译和构建 C++ 项目。

使用 CMake 可以按照以下步骤进行:

1. 新建一个目录并进入,在其中创建或放置源代码文件。

2. 新建一个 CMakeLists.txt 文件,用于配置项目。例如,下面是一个简单的示例:

```
# 指定需要的最低版本号
cmake_minimum_required(VERSION 3.10)

# 设置工程名(项目名称)
project(myproject)

# 添加源代码文件列表
set(SOURCES
    main.cpp
    mylib.cpp
    utils.cpp
)

# 创建可执行文件
add_executable(${PROJECT_NAME} ${SOURCES})
```

在上述示例中:

- `cmake_minimum_required` 定义了需要的最低 CMake 版本。
- `project` 定义了项目的名称。可以通过 `${PROJECT_NAME}` 引用这个名称。
- `set` 声明源代码文件列表。
- `add_executable` 创建可执行文件,并指定名称和所需的源文件列表。

还可以添加其他配置选项,如编译器选项、链接器选项和库信息等。查看 CMake文档以了解更多信息。

3. 进入刚才新建的目录,在终端中执行:

```
cd /path/to/my/project
mkdir build && cd build
cmake ..
```

这将在 `build` 目录中创建 Makefile 文件。

4. 接下来,执行 `make` 命令进行编译和构建:

```
make
```

这将生成可执行文件和其他必要的文件。

CMake 还支持非常多的高级配置选项,例如生成动态库或静态库、为特定平台和系统调整编译配置等。需要注意的是,CMake 不仅可以配置 C++ 项目,也支持其他几十种编程语言和环境。

(2)手写Makefile

一个示例 Makefile 文件:

```Makefile
# 使用GNU编译器
CC = g++
# 编译选项
CFLAGS = -Wall -O2
# 需要编译的源代码文件
SRCS = main.cpp foo.cpp bar.cpp
# 对象文件和可执行文件的名称
OBJS = $(SRCS:.cpp=.o)
EXEC = myprog

# 标准目标:编译可执行文件
all: $(EXEC)

# 生成可执行文件
$(EXEC): $(OBJS)
    $(CC) $(CFLAGS) -o $@ $^

# 生成目标文件
%.o : %.cpp
    $(CC) $(CFLAGS) -c $< -o $@

# 清理生成的文件
clean:
    rm -f $(OBJS) $(EXEC)
```

在上述示例中:

- `CC` 定义了编译器,这里使用了 GNU 编译器 `g++`。
- `CFLAGS` 定义了编译选项,这里设置了 `-Wall` 表示输出所有警告信息,并开启了基本优化(`-O2`)。
- `SRCS` 声明了需要编译的源代码文件列表。
- `OBJS` 和 `EXEC` 分别定义了编译出的对象文件和可执行程序的名称。
- `all` 是 Makefile 的默认目标,指定了如何生成可执行程序。
- `$(EXEC) : $(OBJS)` 表示需要先生成目标文件,然后才能生成可执行程序。
- `$(CC) $(CFLAGS) -o $@ $^` 是链接命令,将指定的目标文件链接成一个可执行程序。
- `%.o : %.cpp` 是模式规则,用于自动生成目标文件。
- `clean` 清理已经生成的目标文件和可执行程序。

在命令行中使用 `make` 命令即可创建项目。另外,`make clean` 命令可以清理已经生成的目标文件和可执行程序。

需要注意的是,Makefile 文件中可能存在缩进符号,请确保所有命令都正确缩进。同时,对于复杂项目,还应该考虑到依赖关系,以确保只重新编译必要的源代码和目标文件。

2.c++添加库(非内置)

C++中添加库的方法取决于您使用的编译器和操作系统。这里给出一些通用的方法供参考:

(1)g++

i. 在源代码中包含头文件(Header Files):在程序中 #include 头文件即可,如:

```
#include <iostream>
```

ii. 在编译时链接库文件(Linking Libraries):库文件大多数情况下是以 .lib 或 .a 的形式出现。如果你使用命令行编译器,则可以通过以下方式链接静态库文件:

```
g++ main.cpp -o myprogram.exe libexample.a
```

其中,main.cpp 是你的源代码,myprogram.exe 是编译后生成的可执行程序,而 libexample.a 是要链接的静态库文件。

iii. 将动态库链接到可执行文件:与静态库相比,动态库更容易管理和更新,并且可以在多个应用程序之间共享。在使用动态库时,您需要确保库文件位于系统的路径中或者将其添加到LD_LIBRARY_PATH环境变量中。

```
g++ main.cpp -o myprogram.exe -L/usr/lib -lexample
```

其中,-L参数指定库文件路径,-lexample 参数指定链接的库名为 libexample.so。请注意,在不同的操作系统或编译器环境下需要使用不同的参数。

(2)Dev c++

i. 下载和安装所需的库文件。您可以从该库的官方网站或其他可信来源下载安装库文件。

ii. 打开Dev-C++,选择 "Tools" 菜单下的 "Compiler Options" 命令。

iii. 在弹出的对话框中,选择 "Directories" 选项卡,并点击右侧的 "Add" 按钮,将库文件添加到 "Include directories" 或 "Library directories" 列表中。
   - 如果要将头文件所在的目录添加到 "Include directories" 中,则将包含头文件的目录路径添加至列表中。如:D:\MyLibs\include
   - 如果要将库文件所在的目录添加到 "Library directories" 中,则将包含.lib文件的目录路径添加至列表中。如:D:\MyLibs\lib

iiii. 在 "Linker" 选项卡里,在 "Link libraries" 中添加库文件名(不包含扩展名),如 MyLib。
   - 如果需要链接多个库文件,请在名称之间使用空格分隔。
   - 如果有多个版本的库文件,请确保所选的版本与您的编译器和操作系统兼容。

iiiii. 点击 "OK" 按钮保存更改,并重新编译并运行您的程序,以确保库文件已正确添加并正常工作。

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 4
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

你好呀zws

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值