-
函數返回值類型+(指針變量名)+(函數傳入的參數)=函數名
第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表示常量的修飾符,可以修飾定義的變量,表示常量不可改變,修飾指針表示指針只能指向固定的位置,修飾指針指向的變量,表示指針指向變量不可修改(但是指針可以指向其他位置),修飾函數表示返回的數據不能修改;
查看全部 -
多態:即是通過繼承虛函數來實現不同子類的具體實現,基類的析構函數設置為虛函數目的是讓子類實現,這樣就可以調用子類的析構過程,進而釋放內存。
查看全部
舉報