-
函数返回值类型+(指针变量名)+(函数传入的参数)=函数名
第25行的代码表示用指针的形式调用函数
dowork()回调函数的用法
查看全部 -
指针可以指向一个数组,例如:
#include <stdio.h>
int main(int argc,char **argv)
{
int arr[] = {1, 2, 3, 4};
int * p = arr;
return 0;
}比较特殊的是,数组名就是一个指针,不过数组名是一个常量指针,不能做累加或者累减操作。
我们可以通过指针来访问数组元素:
*(p + 2)
同样,这句话等价于:
p[2]
查看全部 -
指针可以指向一个变量,例如:
#include <stdio.h>
int main(int argc,char **argv)
{
int a = 0;
int * p = &a;
return 0;
}如果想要通过指针操作变量,只需要使用解引用就可以了:
*p = 20;
查看全部 -
.与->的不同用法
查看全部 -
arr里面放的是数组内第一个元素的地址,等同于&arr【0】
查看全部 -
#include <stdio.h>
int main()
{
int i = 0x1122;
char * p = (char *)&i;
if (p[0] == 0x22 && p[1] == 0x11) {
printf("Little Endian\n");
}
else if (p[0] == 0x11 && p[1] == 0x22) {
printf("Big Endian\n");
}
}判断电脑是哪种字节序
查看全部 -
字节序,就是 大于一个字节类型的数据在内存中的存放顺序。
计算机硬件有两种储存数据的方式:大端字节序(big endian)和小端字节序(little endian)。
我们现在有一个整数是258。用16进制表示是0x0102,然后我们把这个整数拆分成两个字节,第一个字节为 0000 0001,第二个字节为 0000 0010。
如果在一个使用大端字节序的电脑上,这个整数会被这样存放:
如果一个使用小端字节序的电脑上,这个整数的高字节就会存放在高地址上:
现在大部分的机器,都采用了小端字节序。但是在 IO 方面,则大部分使用大端字节序。例如,你要使用网络发送一个 int 类型的变量,要先把 int 转换成大端字节序,然后通过网络发送。
大端字节序又被称之为网络细节序。
查看全部 -
~ 取反
^ 异或
<< 左移
>> 右移
查看全部 -
浮点数会有一定的精度范围,一旦小数点后面位数过多,超出范围,就有可能失去精度。
浮点数的存放复杂,运行起来速度也比较慢,如无必要,还是用整数方便快捷。
查看全部 -
复制一个员工:赋值构造函数
上一小节中,我们介绍了构造函数和析构函数。这一小节,我们来介绍一个特殊的构造函数。
先来看一个例程:
int main(int argc,char **argv) { Staff staffA; Staff staffB = staffA; return 0; }
我们先实例化了一个对象 staffA,然后又实例化了一个对象 staffB。希望 staffB 和 staffA 具有相同的内容,或者说希望 staffB 是 staffA 的副本,那么我们一般直接在实例化的时候进行赋值就可以了。
Staff staffB = staffA;
这样做了之后,C++ 会自动为我们拷贝 staffA 中的成员变量到 staffB 的成员变量中,但是这种自动拷贝机制在某些情况下无法完成我们想要的动作,甚至有可能会出错。我们来具体看一下。
在 Staff 类中添加一些内容:
Staff.hpp
#include <string>
class Staff {
public:
Staff(std::string _name, int _age);
~Staff();
public:
std::string name;
int age;
char * mem = nullptr; };
Staff.cpp
#include "Staff.hpp"
#include <stdio.h>
Staff::Staff(std::string _name, int _age) {
mem = (char *)malloc(20);
name = _name;
age = _age;
printf("构造函数被调用\n");
}
Staff::~Staff() {
if(mem != nullptr){ free(mem); mem = nullptr; }
printf("析构函数被调用\n");
}
在上面的代码中,在类中定义了一个指针,在构造函数中,通过 malloc 函数分配了一个 20 字节大小的堆内存,然后将这片堆内存的首地址赋值给了这个指针。在析构函数中,我们将这片堆内存释放掉。
这个时候,我们再进行一开始的操作:
Staff staffB = staffA;
先来看看 staffA 在实例化之后的内存布局:
mem 指针指向了一片 20 个字节大小的堆内存。
这个时候,再来看看执行了Staff staffB = staffA;之后,staffB 的内存布局会怎么样:
可以看到,在 C++ 默认的复制模式之下,两个对象中的 mem 指针指向了同一片内存。因为 C++ 默认的复制模式只会简单得把成员的值进行复制,面对这个 mem 指针,他只会把指针的值进行拷贝,最后的结果就是 mem 指针指向了同一片内存。
这种拷贝方式,被称之为浅拷贝。
赋值构造函数
Staff staffB = staffA;
当我们使用这种方式实例化对象的时候,并不会调用普通构造函数,而是会调用一个特殊的构造函数,被称之为赋值构造函数或者拷贝构造函数。如果我们没有写,那么就会按照浅拷贝的方式来进行复制。一个拷贝构造函数看起来就像下面这样:
Staff(const Staff & staff);
这个函数中只有一个参数 staff,表示要拷贝的对象,在我们的例子中,就是 staffA。(const 和 & 我们在后续的课程中会具体讲解)
那么我们来完整的编写一下这个函数
Staff.h
#include <string>
class Staff {
public:
Staff(std::string _name, int _age);
Staff(const Staff & staff);
~Staff();
public:
std::string name;
int age;
char * mem = nullptr; };
Staff.cpp
#include "Staff.hpp"
#include <stdio.h>
Staff::Staff(std::string _name, int _age) {
mem = (char *)malloc(20);
name = _name;
age = _age;
printf("构造函数被调用\n");
}
Staff::Staff(const Staff & staff) {
name = staff.name;
age = staff.age;
mem = (char *)malloc(20);
memcpy(mem, staff.mem, 20);
}
Staff::~Staff() {
if(mem != nullptr){ free(mem); mem = nullptr; }
printf("析构函数被调用\n");
}
查看全部 -
函数返回一个绳子:函数返回指针
指针变量其实和普通变量没有什么区别,一个函数也是可以正常返回一个指针的。
char * func() { char * p = nullptr; return p; }
int main(int argc,char **argv) { return 0; }
但是我们需要思考的是,什么情况下我们要返回一个指针,返回指针的时候需要我们注意些什么?通常情况下,我们是希望为函数外提供一片内存,例如,我们可以给函数外面提供一个数组。int * func() { int arr[] = {1, 2, 3, 4}; return arr; }
但是这样写得话,程序会崩溃掉。原因是,arr 数组是一个局部变量,在 func 结束之后,其内存就被销毁掉了。此时在函数外面对其进行操作,自然会出问题。所以,要完成这类操作,我们需要把内存分配到堆内存上面。int * func() { int * arr = (int *)malloc(4 * sizeof(int)); return arr; }
这样就没有问题了,当然,既然是分配在了堆内存上,就要记得手动销毁。int main(int argc,char **argv) { int * p = func(); free(p); return 0; }
查看全部 -
💊吧把v(vv m筋m哦哦看看那几句台词mmnhhy搞个y
查看全部 -
conat修饰成员函数类似c#中的static,不能调用非const函数、不能修改成员变量
查看全部 -
const表示常量的修饰符,可以修饰定义的变量,表示常量不可改变,修饰指针表示指针只能指向固定的位置,修饰指针指向的变量,表示指针指向变量不可修改(但是指针可以指向其他位置),修饰函数表示返回的数据不能修改;
查看全部 -
多态:即是通过继承虚函数来实现不同子类的具体实现,基类的析构函数设置为虚函数目的是让子类实现,这样就可以调用子类的析构过程,进而释放内存。
查看全部
举报