NDK学习之路 - C++基础篇

一、C++初探:

进入C++, C++就开始有面向对象,有类

// C++的标准输出,<<运算符 操作符 重载
    std::cout << "Hello, World!" << std::endl;

1.C语言与C++语言兼容:

方式一:

main 上面的代码

/**
 *
 * C语言编译后的方法标记:test
 * C++编译后的方法标记:Z4testii
 * C语言  和  C++ 语言编译出来的 方法标记不同,是无法完成兼容 C++ 使用 C语言的
 *
 * extern ”C“ 编译器 这部分的代码,以C的形式来编译,就可以对上了
 * 如果不使用extern ”C“,那么Test.c的方法就会以C++的形式编译,成了Z4testii,并不是test,就找不到了
 */
extern "C" {
    #include "Test.h"
}

2.引用类型:

main的上面

/**
 * TODO 为了学习引用类型
 */
 void changeMethod(int& change) {
     change = 6868;
 }

main里面

// TODO C++ 中有一个 新型的类型 叫做 “引用类型”
    int age = 99;

    /*
     * int& 就是C++中的引用类型
     * 下面这句话的意思是:把age 这个内存地址 取了一个标记引用 就是 ageYin
     */
    int& ageYin = age;
    changeMethod(ageYin);

    std::cout << "age:"  << age << std::endl;
    std::cout << "age内存地址:"  << &age << std::endl;

    std::cout << "ageYin:"  << ageYin << std::endl;
    std::cout << "ageYin内存地址:"  << &ageYin << std::endl;

3.字符串

#include <string> // C++ 中的字符串  注意:在iostream中就有string,配合 std 命名空间才能使用
// TODO 字符串
    // test01();

    char string01[] = {'J','A','V','A', '\0'};
    std::cout << "c++ item:" << string01 << std::endl;

    char * string02 = "PHP";
    std::cout << "c++ item:" << string02 << std::endl;

    // string  std  字符串里面的函数 strcpy
    char buffer[20];
    char * charValue = "Kevin C++";
    std::strcpy(buffer, charValue);
    std::cout << "buffer的值是:" << charValue << std::endl;

    std::string str1 = "谢晓峰";
    std::string str2 = "乔峰";
    std::string str3("狄云");
    std::string str4("步惊云");
    std::string *str5 = new string; // new 代表申请内存
    *str5 = "丁典";

    cout << "str1:" << str1 << "str2:" << str2 << "str3:" << str3 << "str4" << str4 << "str5" << *str5 << endl;

    delete str5; // 记得:一旦申请了内存,一定要释放内存

    /**
     * 申请 与 释放 对应表
     * malloc ---> free
     * new ---> delete
     * new 数组 ---> delete []
     */

    // 拼接字符串
    // 为什么能够 + ,这就涉及到 操作符重载,因为string这个类,它实现了 + 操作符重载,所以就能够拼接字符串
    string str6 = str1 + "  " + str3;
    cout << "str6:" << str6 << endl;
    str6.append("结尾...");
    cout << "str6:" << str6 << endl;

    // 这样直接输出, 在Java中 如果输出的是对象,会默调用该对象的toString()方法
    string *str7 = new string;
    *str7 = "九阳神功";
    cout << str7->c_str() /*+ str7->size() + str7->empty()*/ << endl;
    // (*str7).c_str();
    // str7->c_str();

4.命名空间:

::域作用符

命名空间是C++才有的 在C中是没有的

main上面的:

using namespace std; // 使用std命名空间

// TODO 为了学习命名空间
namespace KevinNameSpace { // 定义命名空间
    void kevinMethod() {
        cout << "kevinMethod...." << endl;
    }
};
// 使用KevinNameSpace命名空间
using namespace KevinNameSpace;


namespace PersonSpace {
    // 命名空间是可以内嵌的
    namespace StudentSpace { // 定义命名空间
        void showStudentName() {
            cout << "学生的名字是:杜子腾" << endl;
        }
    }
}
using namespace PersonSpace::StudentSpace; // 使用命名空间
using namespace PersonSpace; // 使用命名空间
/**
 * 命名空间 和 include 对比:
 * 命名空间类似于 Java中的 import 导入就可以取调用里面的 函数 ... 操作
 * include 是文本替换,属于预处理器操作阶段,进行文本替换的操作来处理的,和命名空间 截然不同
 */

int value09 = 9999999;

main里面的

	// 使用命名空间
    // KevinNameSpace::kevinMethod(); // 如果没有使用KevinNameSpace命名空间,就需要使用域作用符
    kevinMethod(); // 使用了KevinNameSpace命名空间,就不需要使用域作用符

    PersonSpace::StudentSpace::showStudentName(); // 如果没有使用 命名空间
    showStudentName(); // 使用了,就可以直接调用,不需要域作用符

    StudentSpace::showStudentName(); // 使用了:using namespace PersonSpace;

    // 域作用符 的其他用法
    int value09 = 9000000;
    cout << value09 << endl;
    cout << ::value09 << endl; // 可以使用到 main方法上面的value09

5.类的定义与使用:

Student.h

#ifndef NDK04_CODE_STUDENT_H
#define NDK04_CODE_STUDENT_H

#endif //NDK04_CODE_STUDENT_H

#pragma once // 是在预处理器 只保证引入一次,但是可能很多的编译器不支持,所以就需要以下的这种写法

#include <iostream>

#ifndef STUDENT_H // 如果没有定义这样一个宏,
#define STUDENT_H // 那么就定义这个宏

class Student
{
    // 默认是 private 私有的
    int age;

public:
    Student(); // 构造函数
    Student(int age, int age2, int age3); // 构造函数
    Student(int age, int age2); // 构造函数
    ~Student(); // 析构函数

private:
    int age2;

protected:
    int age3;

private:
    int privT01;
    int privT02;
    int privT03;

public:
    int * value01;
    char * value02;
    void setAge(int age);

    /**
     * 常量函数
     * 在函数的后面 增加了 const 就是属于了常量函数
     * 常量函数 不允许修改类中的成员了
     */
    void setAge2(int age2) const ;
    void setAge3(int age3);

    void setPrivT01(int privT01);

    // 声明一个友元函数
    friend void updateField(Student *);

    // 声明一个友元类 Person,此Person就能够操作Student中的私有 不可访问的 成员变量了
    friend class Person;
};

// 此类想要能够访问Student类,此类需要成为友元类
class Person {

    void updateStudentMethod(Student * student) {
        student->privT01 = 11111111;
        student->privT02 = 21111111;
        (*student).privT03 = 31111111;
    }

};

#endif

Student.cpp

#include "Student.h"

using namespace std;

Student::Student() { // 对应头文件中 构造函数的实现
    cout << "构造函数执行了..." << endl;
}

Student::Student(int age, int age2, int age3) {
    this->age = age;
    this->age2 = age2;
    this->age3 = age3;
    cout << "3参 有参构造函数执行了 值是 age:" << age << " age2:" << age2 << " age3:" << age3 << endl;

    this->value02 = (char *) malloc(10 * sizeof(char));
}

Student::Student(int age, int age2) :age(age), age2(age2) {
    cout << "2参 有参构造函数执行了 值是 age:" << age << " age2:" << age2 << endl;
}

void Student::setAge(int age) {
    this->age = age;
    this->value01 = (int *) malloc(10 * sizeof(int));
}

void Student::setAge2(int age2) const {
    // 常量函数,不能修改类中的成员变量了
    // this->age2 = age2;
}

void Student::setAge3(int age3) {
    this->age3 = age3;
}

void Student::setPrivT01(int privT01) {
    this->privT01 = privT01;
}

/**
 * 这个析构函数,可以完成一些收尾工作
 * 例如:在构造方法中,使用了malloc,可以在析构函数中去free
 */
Student::~Student() { // 对应头文件中,析构函数的实现
    cout << "析构函数执行了..." << endl;

    // 让析构函数有一个责任:就是可以去释放当前Student类中,在堆中开辟申请的内存空间
    free(this->value01);
    this->value01 = NULL;

    free(value02);
    this->value02 = 0;
}

6.单例模式

头文件:MyInstance.h

#include <iostream>

class MyInstance {

private:
    static MyInstance * instance;

    MyInstance();

    ~MyInstance();

public:

    static MyInstance * getInstance();


    void show();
    void show2();

    // 给外界提供释放单例的
    void unInstance();
};

MyInstance.cpp

#include "MyInstance.h"

#include "mylog.h"

// #define LOGD(...)__android_log_print(ANDROID_LOG_DEBUG, TAG, __VA_ARGS__)

/**
 * 注意:把MyInstance * 理解成返回值
 */
MyInstance * MyInstance::instance;
MyInstance::MyInstance() {
    // LOGD("我是无参构造函数");
    // __android_log_print(ANDROID_LOG_DEBUG, "TAG", "我是无参构造函数");
}

MyInstance::~MyInstance() {
    LOGD("此单例模式被释放了...");
}

MyInstance * MyInstance::getInstance() {

    // 伪代码
    /*if (instance == null) {
        锁
        if(instance == null) {
            new ...
        }
    }*/

    // C++11之后,内部会自动保证,所有static成员变量,线程的安全问题,内部已经处理好了,我们不用关心了
    if(!instance) { // instance == null
        instance = new MyInstance();
    }
    return instance;
}

void MyInstance::show() {
    LOGD("show");
}

void MyInstance::show2() {
    LOGD("show2");
}

// 释放单例
void MyInstance::unInstance() {
    if (instance) {
        delete instance;
        instance = nullptr;
    }
}

7.运算符重载

第一种方法:重载运算符+,类中定义。

class MyOperate {
public:
    MyOperate(int i, int j) : i(i), j(j) {}

    MyOperate() {};
public:
    int i;
    int j;

public:  MyOperate operator + (MyOperate &myOperate) {
        MyOperate temp;
        temp.i = myOperate.i + this->i;
        temp.j = myOperate.j + this->j;
        return temp;
    }
};

使用:

 MyOperate myOperate1(1,3);
 MyOperate myOperate2(4,6);
 MyOperate andtemp = myOperate1+myOperate2;

第二种方法: 类外定义

// TODO 另外一种运算符重载
class MyOperator2
{
public:
    int count;
};
MyOperator2 operator + (MyOperator2 m1, MyOperator2 m2)
{
    MyOperator2 temp;
    temp.count = m1.count + m2.count;
    return temp;
}

 使用和第一种方法一样


特殊字符的重载,可用于监控创建对象和回收对象。

// TODO 特殊的一些操作符
void * operator new (size_t size) {
    LOGD("谁又new了,大小是:%d", size);
    return malloc(size);
}
void operator delete(void * p) {
    LOGD("谁delete了,内存地址是:%#x", p);
}

下面是可重载的运算符列表:

双目算术运算符+ (加),-(减),*(乘),/(除),% (取模)
关系运算符==(等于),!= (不等于),< (小于),> (大于>,<=(小于等于),>=(大于等于)
逻辑运算符||(逻辑或),&&(逻辑与),!(逻辑非)
单目运算符+ (正),-(负),*(指针),&(取地址)
自增自减运算符++(自增),--(自减)
位运算符| (按位或),& (按位与),~(按位取反),^(按位异或),,<< (左移),>>(右移)
赋值运算符=, +=, -=, *=, /= , % = , &=, |=, ^=, <<=, >>=
空间申请与释放new, delete, new[ ] , delete[]
其他运算符()(函数调用),->(成员访问),,(逗号),[](下标)

下面是不可重载的运算符列表:

  • .:成员访问运算符
  • .*, ->*:成员指针访问运算符
  • :::域运算符
  • sizeof:长度运算符
  • ?::条件运算符
  • #: 预处理符号

详解实例参见:C++ 重载运算符和重载函数 | 菜鸟教程


8.继承

基类

关键字:virtual 定义虚函数。

class Person
{
private:
    int age;
    char sex;
public:

    char * name = "Kevin";

    //普通函数
    void show01() {
        LOGD("fuShow run ...");
    }

    // 虚函数
    // Parent things= new Chlid();
    //这种方式的对象会 执行子类的实现。 
    //普通函数则调用父类的实现
    virtual void show04() {
        LOGD("fuShow4 run ...");
    }

    // 纯虚函数 == Java的抽象方法 
    //子类必须实现该方法
    virtual void show05() = 0;// 0 == NULL
};

子类 

// 子类
// 如果是 : Person 就 == private Person
// private Person 子类自力更生,永远不用父类的成员(只是建立子父关系)
class Workder : public Person, protected Person2, private Person3, Person4
{
public:
    void show01() {
        LOGD("ziShow run ...");
    }


    void show04() {
        LOGD("ziShow4 run ...");
    }

    void show05() {
        LOGD("ziShow5 run ...");
    }
};

继承的三种方式:

 在这里插入图片描述


9.虚函数/纯虚函数

关键字:virtual 定义虚函数。

虚函数:

纯虚函数:声明如下: virtual void funtion1()=0;虚函数一定没有定义,纯虚函数用来规范派生类的行为,即接口

10.模板编程

对比学习Java中的泛型。

定义

// 函数模板 == Java泛型方法
template <class T>
T max(T number1, T number2) {
    return number1 > number2 ? number1 : number2;
}
// 类模板 == Java泛型类
template <class Q, class P>
class TestClass {
public:
    P getP(P p) {
        return p;
    }

    Q getQ(Q q) {
        return q;
    }
};

 简单使用

 // 使用函数模板
    max(1000000, 2000000);
    max('M', 'w');
    max("你好", "我好");
    max("步惊云", "乔峰");
    max(3466436.4564, 34645644.5346);

    // 使用类模板
    TestClass<long , string> testClass;
    string pValue = testClass.getP("许三多");
    long qValue = testClass.getQ(9999999);

10.类型转换

// 静态类型的转换 (涉及的是指针类型相关的转换操作)
// 静态多态--编译时期
ZiClass *ziClass = static_cast<ZiClass*>(fuClass);
动态类型的转换 -- 运行时期
ZiClass *ziClass = dynamic_cast<ZiClass *>(fuClass);

  • 基本数据类型转换
    // TODO 类型转换
    // C++的新式转换 转换操作符
    // const_cast:主要是 修改类型的const
    const char *c1 = "#x001241";
    char* c2 = const_cast<char*>(c1);

    char * c3 = "#x581545";
    const char * c4 = const_cast<const char*>(c3);
  •  类类型转换
    // TODO 为了学习转换
    class Person {
    public:
        virtual void show() {
            cout << "父类 Person show" << endl;
        }
    };
    
    class Student : public Person {
    public:
        void show() {
            cout << "子类 Student show" << endl;
        }
    };
    	// C++的静态转换 转换操作符
        // static_cast:
        // 1.基础类型的互转,例如:int转float,int转unsigned init 等操作
        // 2.指针与void之间的互转,例如:float* 转 void* , 函数指针 转 void* 等操作
        // ...
        Person * person = new Person;
        Student * student = static_cast<Student*>(person);
        student->show();
        delete person;  // 回收的规则,一定是 谁new了,我就回收谁*/
    
        // 如果不想使用 以上类型的 类型转换操作符,也可以使用 “强制类型转换”

    11.异常

异常函数的定义/ 自定义异常

// TODO 为了学习异常
void exceptMethod01() {
    throw "我报错了,9527...";
}
void exceptMethod02() {
    throw exception("我报废了,9687.。。");
}
// 自定义异常
class CustomExceptionClass : public exception
{
public:
    virtual char const* what() const
    {
        return "CustomExceptionClass 自定义异常";
    }
};
void exceptMethod03() {
    CustomExceptionClass c;
    throw c;
}

// 随便自定义一个类,作为异常类,都是可以的,抛出一个对象作为异常
class Dog
{
public:
    char * name;
    void showName() {
        cout << "捕获到exceptMethod04函数发生了异常: shouName:" << this->name << endl;
    }
};
void exceptMethod04() {
    Dog d;
    d.name = "阿黄";
    throw d;
}

异常函数调用

// TODO 异常
    try {
        exceptMethod01();
    } catch (const char* exceptionMessage) {
        cout << "捕获到exceptMethod01函数发生了异常,异常详情:" << exceptionMessage << endl;
    }

    try {
        exceptMethod02();
    } catch (exception &e) {
        cout << "捕获到exceptMethod02函数发生了异常,异常的信息:" << e.what() << endl;
    }

    try {
        exceptMethod03();
    } catch (CustomExceptionClass &exceptionClass) {
        cout << "捕获到exceptMethod03函数发生了异常,信息是:" << exceptionClass.what() << endl;
    }

    try {
        exceptMethod04();
    }catch (Dog &d) {
        d.showName();
    }

12.常量函数

摘录:https://www.cnblogs.com/xinxue/p/5405362.html

  常量成员函数 (const member function), 可读取类中的数据成员,但不能修改 

1.1  const 关键字

参数列表后,加 const 关键字,声明为常量成员函数,表明其不被允许修改类的数据成员

  下面的类,以年、月、日的形式来表示日期 (注意:年月日的声明顺序)

class Date {
public:
    int GetYear() const { return y_; }int GetMonth() const { return m_; }
    int GetDay() const { return d_; }
    void AddYear(int n); // add n years
private:
    int y_, m_, d_;  
};

1) 如果常量成员函数,企图修改类的数据成员,则编译器会报错

// error : attempt to change member value in const function
int Date::GetYear() const
{
    return ++y_; 
}

  2) 如果在类外面,“定义” 常量成员函数 ( “定义” = 实现,即 implementation),则 const 关键字不可省略

// error : const missing in member function type
int Date::GetYear() 
{
    return y_;
}

1.2  陷阱

 类中成员变量的声明顺序,决定了成员变量的初始化顺序。假设 Date 类中的构造函数为:

public:
    Date() : y_(2016), m_(9), d_(22) {}

 此时,类中的成员函数,在类中的声明顺序 = 构造函数初始化列表顺序,故 y_, m_, d_ 都能被顺利的初始化为对应的值。

  而当成员变量,在类中的声明顺序 ≠ 构造函数初始化列表顺序 时,

public:
    Date() : y_(2016), d_(22), m_(d_-13) {}

  根据成员变量的声明顺序,y_ 首先被初始化为 2016,然后再初始化 m_,但由于 d_ 并未被初始化,所以 m_ 的值是随机的,最后初始化 d_ 为 22

  这是因为,类的成员变量在初始化时,其初始化的顺序只与声明顺序有关,而与在初始化列表中的顺序无关。


13.vector容器

序列式容器 vector:

导入:

#include <vector> // // C++ 容器中提供的

 api的调用

 // C++  中容器,分为两种类型
    // 1.序列式容器:元素的排序关系,和元素本身没有任何关系,是我们在添加的时候导致的顺序导致的排序
    // vector    priority_queue
    vector<int> vec01(1); // 声明一个元素的空间
    vector<string> vec02(100, "杜子腾"); // 声明100个元素空间,值都是=“杜子腾”

    vector<string> vec03;
    // 添加元素
    vec03.push_back("杜子腾");
    vec03.push_back("戴乐静");
    vec03.push_back("史珍香");
    // 删除元素
    vec03.pop_back(); // 删除最新的,最后添加的元素,删除“史珍香”

    //插入指定元素
    vec03.insert(*allName.end() - 1, "ff");

    //删除指定元素
    vec03.erase(*vec03.begin()+1);

    // 获取元素
    string value = vec03.at(0);
    value = vec03[1];
    cout << value << endl;

    // 清空元素
    vec03.clear();
    // vec03.erase(vec03.begin(), vec03.end());

    // 是否被清空了
    if (vec03.empty()) {
        cout << "元素被清空" << endl;
    } else {
        cout << "元素没有被清空" << endl;
    }

    // 容器有很严重的问题
    // 此容器,占用的内存空间,是只增不减的
    cout << "此Vector容器,占用内存空间是:" << vec03.capacity() << endl;

    // 全局问题演示
    test01();

    return 0;

注意clear()函数的坑

容器被清空之后vec03.capacity()还是有占位的,且只增不减。正常在栈中实例化的,弹栈后即可回收,但如果有全局的vector,则需想办法回收

// 想办法让容器有问题, 全局
vector<string> allName;

void test01() {
    allName.push_back("1111");
    allName.push_back("2222");
    allName.push_back("3333");
  
    allName.clear(); // 清空 内存空间 还是占用的  怎么办?

    // 替换的方式:来解决此问题
    vector<string> tempVector; // 定义临时容器目的:就是为了解决 、 替换全局容器,让全局容器不占用内存空间
    tempVector.swap(allName); // 把全局的 全部移动 给临时 == 把全局的给回收了
} // 函数一弹栈  tempVector给回收了,就保证了,全局和临时全部回收完毕

14.priority_queue:优先级队列

#include <queue> // C++ 容器中提供的

传统方式 

    // 优先级队列 是在vector之上实现的,所以只能写vector<T>
    priority_queue<int> priorityQueue;
    priorityQueue.push(6);
    priorityQueue.push(9);
    priorityQueue.push(1);
    // 值最大的 在第零个元素 也就是 top
    cout << "priority_queue.top():" << priorityQueue.top() << endl;

    // 调整 队列  下面这句话的意思就是,优先级队列是基于vector来实现的
    priority_queue<int> priorityQueue2(int, vector<int>, greater<int>);
    // priority_queue<int> priorityQueue2(int, vector<int>, less<int>);
    // less:代表最大的元素在最前面
    // greater:代表最小的元素在最前面

 自定义方式

定义:

// TODO 为了学习优先级队列 priority_queue
class MyType
{
public:
    int count;

    MyType(int count) {
        this->count = count;
    }
};

// 自定义排序规则,才能给 MyType这个类,进行排序
struct MyTypeLess { // functor for operator<
    // C++ 在结构体可以写函数
    constexpr bool operator()(const MyType& _Left, const MyType& _Right) const {
        return _Left.count < _Right.count;
    }
};

引用:

    // 由于此优先级队列,不知道如何给这个MyType类排序,而出现的错误
    priority_queue<MyType, vector<MyType>, MyTypeLess> pqMyType;
    pqMyType.push(MyType(1));
    pqMyType.push(MyType(9999992));
    pqMyType.push(MyType(3));
    cout << "pqMyType.top():" << pqMyType.top().count << endl;

15.关联式容器 set

#include <set>
// ---- 关联式容器
    // 通过一个关键字 来保存 和 访问 元素的  例如:Java中的 map  set 都是关联式容器
    set<int> set1 = {1,2,3,4,5};
    set1.insert(999);
    set1.insert(888);
    set1.insert(777);
    set1.insert(1); // 重复的元素添加不进去,因为set不允许 添加重复的元素
    set1.insert(2); // 重复的元素添加不进去,因为set不允许 添加重复的元素
    set1.insert(3); // 重复的元素添加不进去,因为set不允许 添加重复的元素
    cout << "set1.size:" << set1.size() << endl;

    // 删除元素
    set1.erase(1);

    pair<set<int>::iterator, bool> pair1 = set1.insert(1900000);

    // 使用迭代器
    set<int>::iterator beginResult = set1.begin(); // 指向容器中 第零个元素
    set<int>::iterator endResult = set1.end(); // 指向容器中,最后一个 的下一个元素
    cout << "beginResult:" << *beginResult << endl;
    // 遍历set
    for (; beginResult != set1.end() ; beginResult++) {
        cout << "遍历set it:" << *beginResult << endl;
    }

    // 遍历vector
    vector<string> vectorStr;
    vectorStr.push_back("11");
    vectorStr.push_back("22");
    vectorStr.push_back("33");
    vectorStr.push_back("44");
    vectorStr.push_back("55");
    vectorStr.push_back("66");
    vector<string> :: iterator  it = vectorStr.begin();
    for (; it < vectorStr.end() ; it ++) {
        cout << "遍历vector:" << *it << endl;
    }

    // -----
    // map
    map<int, string> map1;
    map<int, string> map2 = { {1, "a"}, {2, "b"} }; // 不能有重复的元素和set一样
    map2[2] = "bbb";

16.文件流 

导入库

#include <iostream>
#include <ostream> // 输出
#include <istream> // 输入
#include <fstream>

C语言的文件流操作:

// TODO 文件流
    // 文本的形式 写入
    FILE* file1 = fopen("D:\\NDK\\NDK\\CoursewareCreate\\ndk_05\\file.txt", "w"); // w:代表可写
    // 在Windows上 文件格式是 GB2312的,在Mac上有乱码的
    fprintf(file1, "今天是%d号。", 11);
    fclose(file1); // 一定要关闭,和Java中的一样

    // 文本的形式 读取文件
    FILE* file2 = fopen("D:\\NDK\\NDK\\CoursewareCreate\\ndk_05\\file.txt", "r"); // r:代表可读
    char buffer[1024]; // 最大可以读取1023个字节,+ /0
    fscanf(file2, "%s", buffer); // 如果遇到,空格,就直接返回了 结束读取
    cout << "文件的内容是:" << buffer << endl;
    fclose(file2);

    // // 如果遇到,空格,就直接返回了 结束读取, 所以需要 循环读取
    FILE* file3 = fopen("D:\\NDK\\NDK\\CoursewareCreate\\ndk_05\\file2.txt", "r"); // r:代表可读
    char buffer2[1024]; // 最大可以读取1023个字节,+ /0
    while(!feof(file3)) {
        fscanf(file3, "%s", buffer2);
        cout << "文件的内容是:" << buffer2 << endl;
    }
    fclose(file3);

    // 遇到 换行,/0 都会结束读取, 读取1024个字节
    FILE* file4 = fopen("D:\\NDK\\NDK\\CoursewareCreate\\ndk_05\\file2.txt", "r"); // r:代表可读
    char buffer3[1025]; // + /0
    fgets(buffer3, 1024, file4); // 读取1024个字节,这种很明确
    cout << "file4:" << buffer3 << endl;
    fclose(file4);

  

 C++操作文件流:

char * file = "D:\\NDK\\NDK\\CoursewareCreate\\ndk_05\\file3.txt";

    // 写入
    char data[200];
    ofstream outFile; // 以写的模式去打开文件
    outFile.open(file);

    // 捕获用户在控制台输入信息
    cout << "请您输入您要保存的信息:" << endl;
    cin >> data; // 接收终端的输入信息,赋值给 data

    // 把数据data 写入到文件中去
    outFile << data << endl;

    // 关闭上面打开的文件
    outFile.close();

    // -- 读取
    char myData[200];
    cout << "开始 自动的去读取 刚刚保存到文件里面的内容...." << endl;
    ifstream ifstreamVar;
    ifstreamVar.open(file);
    ifstreamVar >> myData;
    cout << myData << endl;
    // 关闭
    ifstreamVar.close();

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值