C++ Primer Plus第七章 函数——C++的编程模块

        

目录

1、C++函数的定义与声明

 函数声明:

函数定义:

2、函数与数组

        啊哈哈哈,本打工人先大跨一下,因为确实前面六章对于熟悉过C语言的同学来讲属于基础内容,作者准备从第七章先继续阅读总结,但是前六章我一定会回过头回去定时续更,确实是目前时间紧,工作日还是要打工的嘛,像读者们保证~~

1、C++函数的定义与声明

 函数声明:

        就是告诉编译器函数的名称、返回类型以及参数的类型和数量。它不包含函数体,即不包含实际执行的代码。函数声明通常在头文件(.h 或 .hpp 文件)中进行。

        说白话,其实就是告诉编译器,小哥要写函数了,他是什么类型的,会用到一些什么样子的参数、返回值等。但是小哥有点忙,回头再给他准确定义,而编译器你只要知道我后面会写就够了,写好了你在拿去用。

函数定义:

        函数定义包括函数的声明和函数体。函数体是函数执行的代码,它实现了函数声明中描述的功能。其实就是你希望上面声明的函数到底里面怎么搞,就好比你说你要做番茄鸡蛋,你在这里告诉计算机我的鸡蛋怎么炒,番茄什么时候炒,放多少调味料。也就是程序要在这里给他实现了。

2、函数指针与数组

        数组是一种基本的数据结构,用于存储固定大小的相同类型的元素集合。都吃过超市里趣某多的曲奇饼干吧,里面放饼干的塑料壳子,就可以理解为数组。你可以把饼干按顺序的放入开辟好的数组里,同时,你可以可以选择按顺序吃饼干,也可以指定位置直接吃饼干。

定义数组

        数组可以通过指定元素类型和数组大小来定义。以下是举例的一些简单示例,后面有时间的话,我会把数组的用法也续更在这里,但是现在是时间紧迫哈,暂时就不细更了,我只能先插眼,等我兄弟们!

int numbers[10];//定义数组
int numbers[5] = {1, 2, 3, 4, 5};//初始化数组
int firstElement = numbers[0]; // 访问第一个元素
int lastElement = numbers[4];  // 访问最后一个元素
int arraySize = sizeof(numbers) / sizeof(numbers[0]);
int matrix[3][2] = {   //多维数组
    {1, 2},
    {3, 4},
    {5, 6}};
int* dynamicArray = new int[10];//动态数组
const int constantNumbers[5] = {1, 2, 3, 4, 5};//常量数组

函数指针

        谈到数组,那肯定离不开指针。还记着我当时刚入门C的时候被指针硬控的日子,直接回想起来快流泪了。不过指针还是核心的,一定要好好理解透彻。

        先上定义,函数指针是一种特殊的指针,它指向一个函数。函数指针可以用来存储函数的地址,从而可以在运行时调用不同的函数。这对于实现回调函数、事件处理系统、策略模式等高级编程技术非常有用。

        好了,定义上完了,我要说白话了,咱们就拿数组举例吧。在大多数情况下,C++和C语言一样,也将数组名视为指针,C++将数组名解释为其第一个元素的地址。举个例子:

#include <iostream>

int main() {
    int numbers[5] = {10, 20, 30, 40, 50}; // 定义一个整型数组
    int *ptr = numbers; // 定义一个整型指针并指向数组的第一个元素

    // 使用指针遍历数组
    for (int i = 0; i < 5; i++) {
        std::cout << "Element at index " << i << " is: " << *(ptr + i) << std::endl;
    }

    // 也可以直接使用指针进行访问
    for (int i = 0; i < 5; i++) {
        std::cout << "Element at index " << i << " is: " << ptr[i] << std::endl;
    }

    // 使用指针进行数组元素的修改
    for (int i = 0; i < 5; i++) {
        *(ptr + i) = *(ptr + i) * 2; // 将数组中的每个元素乘以2
    }

    // 打印修改后的数组
    for (int i = 0; i < 5; i++) {
        std::cout << "Modified element at index " << i << " is: " << *(ptr + i) << std::endl;
    }

    return 0;
}

       通过上述的案例,大家简单有点感觉了嘛?我记着我之前看过一本书,作者把指针和数组比喻成家与门牌号之间的关系。比如家就是数组,你的家里的房间就是里面的容量,比如home[4],这就是你的四室一家,我给里面每个房间标上门牌号0,1,2,3,这就是home[0],home[1],home[2],home[3]。

        然后我觉着直接喊0,1,2,3太无聊了,我整了个Ikun的门贴,贴在哪个房间就从哪个房间开始做卫生,那我就从0号房间开始贴吧,我给起名叫int *ikun=home,这个ikun就是指针,指向房间0。如果我后面想指向2号房,我就只需要给他+2移过去就可以。

下面咱们来区分两个容易混淆的问题:

  1. 常量指针:这是一个可以改变指向的指针,但它指向的值是常量,不能通过这个指针修改其指向的值。换句话说,指针本身可以指向不同的地址,但是一旦指向了一个地址,就不能通过这个指针来修改指向的值。

  2. 指针常量:这是一个指针,它的指向是固定的,不能改变指向,但它指向的值是可以修改的。换句话说,一旦指针被初始化后,就不能指向其他地址,但是可以通过这个指针来修改它指向的值。

    #include <iostream>
    
    int main() {
        int var = 10;
        const int *ptr = &var; // 常量指针,指向var
    
        std::cout << "Value of var: " << *ptr << std::endl; // 允许
        // *ptr = 20; // 不允许,不能通过常量指针修改指向的值
    
        // ptr = &var + 1; // 允许,可以改变指针的指向
        return 0;
    }
    
    
    
    
    #include <iostream>
    
    int main() {
        int var1 = 10;
        int var2 = 20;
        int *const ptrConst = &var1; // 指针常量,指向var1
    
        std::cout << "Value of var1: " << *ptrConst << std::endl; // 允许
        *ptrConst = 30; // 允许,可以通过指针常量修改指向的值
    
        // ptrConst = &var2; // 不允许,不能改变指针常量的指向
        return 0;
    }

 多维数组

        多维数组是数组的数组,就像我们生活中的矩阵一样,可以有多个维度。在C++中,最常见的多维数组是二维数组,它类似于一个表格,有行和列。

#include <iostream>

int main() {
    // 定义一个5行3列的二维数组并初始化
    int table[5][3] = {
        {1, 2, 3},
        {4, 5, 6},
        {7, 8, 9},
        {10, 11, 12},
        {13, 14, 15}
    };

    // 访问并打印二维数组的元素
    for (int i = 0; i < 5; i++) { // 行循环
        for (int j = 0; j < 3; j++) { // 列循环
            std::cout << table[i][j] << " ";
        }
        std::cout << std::endl; // 每打印完一行换行
    }

    return 0;
}
注意事项
  • 多维数组的存储方式是按行优先的,即数组元素在内存中是按行依次存储的。
  • 多维数组的维数过高会增加复杂性,通常不建议使用超过三维的数组。
  • C++标准库提供了std::vector来替代数组,如果需要动态大小的多维数组,可以考虑使用嵌套std::vector

在C++中,结构体(struct)是一种用户自定义的数据类型,可以包含多个不同类型的成员。结构体可以通过值传递和地址传递两种方式传递给函数。

传递结构体

通过值传递:这种方式会将结构体的所有数据复制到函数内部,因此对结构体的修改不会影响原始数据。

通过地址传递:这种方式传递的是结构体的地址,函数内部通过指针来修改结构体的内容,因此对结构体的修改会影响原始数据。

#include <iostream>

// 定义一个结构体
struct Person {
    std::string name;
    int age;
};

//通过值传递
void modifyByValue(Person p) {
    p.age = 30; // 修改结构体的age成员
    std::cout << "Inside modifyByValue: " << p.name << " is now " << p.age << " years old." << std::endl;
}

int main() {
    Person person = {"John", 25};
    std::cout << "Before modifyByValue: " << person.name << " is " << person.age << " years old." << std::endl;
    modifyByValue(person);
    std::cout << "After modifyByValue: " << person.name << " is " << person.age << " years old." << std::endl;
    return 0;
}

//通过地址传递
void modifyByAddress(Person *p) {
    p->age = 30; // 修改结构体的age成员
    std::cout << "Inside modifyByAddress: " << p->name << " is now " << p->age << " years old." << std::endl;
}

int main() {
    Person person = {"John", 25};
    std::cout << "Before modifyByAddress: " << person.name << " is " << person.age << " years old." << std::endl;
    modifyByAddress(&person);
    std::cout << "After modifyByAddress: " << person.name << " is " << person.age << " years old." << std::endl;
    return 0;
}

        通过地址传递结构体通常更高效,特别是对于大型结构体,因为它避免了数据的复制。然而,它也可能导致原始数据被意外修改,因此在设计函数时需要谨慎考虑。

总结

  • 通过值传递:函数内部的修改不会影响原始数据,因为传递的是数据的副本。
  • 通过地址传递:函数内部的修改会影响原始数据,因为传递的是数据的地址。

 

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值