1.數組與*符號在某種情況下等價。
當作爲函數的入參的時候,
2.數組變量是指針常量
如下代碼,註釋掉一行,這一行是不對的,我們知道,字符串是一個存儲與字符串常量區的地址。a=“jjj”;表示把這個地址賦值給a ,但是a是一個指針常量,相當於const char *p="hello"
後面是不允許我們作修改的。
char a[]="hello";
printf("%s\n",a);
// a="jjj";
strcpy(a,"jjj");
printf("%s\n",a);
3.ifndef
這個只是防止頭文件重複包含,只針對同一個文件多次包含,不是針對所有文件,所以理論上一個變量在頭文件定義會導致重複定義的問題
頭文件只建議使用聲明
//a.h文件聲明
extern int a;
//a.c文件定義
int a=0;
//main.c
include "a.h"
關於全局 變量的問題
//a.c文件中,是正確的,這表示聲明而已,而不是定義
int a;
int a;
int a;
//但是下面出現=符號表示定義,就不能有多個了。
int a=9;
malloc 是在堆區中分配內存的
變量是存儲與棧區,系統是會自動進行回收的。但是對於 malloc 分配的內存,如果不使用free進行釋放,會導致內存泄露
結構體可以通過=進行賦值
struct Student p1={12,"blueboz",88};
struct Strudent p2=p1;
//如果使用指針類型,不能
struct Student *p3;
//不能直接進行賦值,否則會導致段錯誤
p3->age=19;//此行錯誤
p3=&p1;//纔可以操作
//下面直接操作Student裏面的info 會導致段錯誤。因爲指針沒有指向,最好使用非指針
struct Info{
int age;
char name[50];
};
//1.struct 是關鍵字
//
struct Student{
int age;
char name[50];
int score;
struct Info *info;
};//有分號
a[0] 與 *(a+0) 與 *(a)是等價的
const修飾的指針
struct Student tmp;
//const 修飾的是* 指針指向的內存無法進行修改
const struct Student *p2=&tmp;
struct Student const *p2=&tmp;
//const 修飾的是p2,指針指向不能修改,但是指針指向的內容是可以修改的
struct Student * const p2=&tmp;
//指針指向無法修改,指針指向的內容也無法修改
const struct Student * const p2=&tmp;
爲什麼void類型變量不存在而void 類型指針存在
因爲對於不同類型的變量,首先我們需要確定的是他佔用的空間的大小,但是void類型我們並無法確定,但是對於指針類型卻是可以的,因爲指針類型佔用的空間大小完全由操作系統決定的。對於32位操作系統,指針佔用的大小是4字節,對於64位,佔用的8字節。
內存四區
堆區,棧區,全局區,代碼區。
只要放在大括號裏面的變量都是局部變量,只要放在大括號外面的變量都是全局變量。
全局區:全局變量和靜態變量,裏面分爲初始化區和未初始化區。文字常量區:字符常量區。整個程序運行完畢,自動回收。
常量區:字符串常量和其他的常量的存儲位置,程序完成之後自動釋放。
注意,常量也是放在全局區。
數據類型別名
//定義u32爲unsigned int
typedef unsigned int u32;
//定義結構體的別名
typedef struct People{
char name[64];
} People;
數據類型本質
數據類型本質是固定內存大小的別名;是個模具,c語言規定:通過 數據類型定義變量
堆棧的生長方向
先定義的變量擁有高的地址,後定義的有低的地址,但是數組是擺放是按照從低到高的方式。
如圖 8c > 88 ,但是有意思的是,數據後定義,居然地址是在高位的?跟書上說的不一樣,暫且不深究了。
Mac 實現system(“pause”)
system("read -n 1 -s -p \"Press any key to continue...\"");
字符串反轉
通過一個頭指針,一個尾指針,相互交換內容效率很高。比傳統的遞歸方式效率要高很多。大概是5倍左右。
/**
* @brief inverse 交換指針指向內容
* @param org
* @return
*/
void inverse(char *org){
//str =012345
int len=strlen(org);
char* start=org;
char* end=org+len-1;
char tmp=0;
while(end>start){
tmp=*end;
*end=*start;
*start=tmp;
end--;
start++;
}
}
查看棧大小
➜ build-dm01-Desktop_Qt_5_13_1_clang_64bit-Debug limit
cputime unlimited
filesize unlimited
datasize unlimited
stacksize 8MB
coredumpsize 0kB
addressspace unlimited
memorylocked unlimited
maxproc 2784
descriptors 2560
導航文章
Linux各類limit設置
指針數組的理解
指針本是一種類型,但又說什麼類型的指針,只不過是說指針所指向的 數據是什麼類型而已。那麼指向數組類型的指針,就只好叫數組指針。
int a[10]; //a的類型是⼀一個指向int類型的指針。
&a; //&a的類型是⼀一個指向數組int[10]類型的指針。
宏定義
要注意,宏定義一般都是直接展開的。遇到if else 語句可能會發生問題。
#define SAFE_DELETE(p) \
do{ \
free(p); \
p=NULL; \
} while(0);
類似如下宏定義就存在着一定的問題。
#define macro(condition) \
if(condition) dosomething()
如果是直接展開,那麼就會有問題。
if(temp)
macro(i);
else
doAnotherThing();
else 變成了與macro裏面的if 進行結合。這也是爲何建議使用do while(0)的原因了。
結構體字節對齊
就算是一樣的結構體,但是你定義的位置不一樣,導致最終所佔用的空間也是不一樣的。
struct Sutdent{
double d; //8 8*1=1 2 3 4 5 6 7 8
char c; //1 1*9=9
short s; //2 2*5=11 12
int i; //4 4*3=13 14 15 16
//佔用16字節
};
struct Student{
char c; //1*1=1
double d; //8*1=9 10 11 12 13 14 15 16
short s; //2*8=17 18
int i; //4*5=21 22 23 24
//佔用24 字節
};
可以採用如下的命令來執行字節對齊。
字節對齊可以程序控制,採用指令:
#pragma pack(xx)
#pragma pack(1)
#pragma pack(2)
#pragma pack(4)
#pragma pack(8)
#pragma pack(16)
//1字節對⻬齊 //2字節對⻬齊 //4字節對⻬齊 //8字節對⻬齊 //16字節對⻬齊
文件操作
其實記住上面的表也很簡單,其實核心操作就是r w a 即讀寫追加
b,只是爲了塊讀寫操作。。+表示額外賦權,即寫有讀,讀有寫
memwatch 使用
首先是將頭原件與源代碼引入到項目中。
其次添加宏,可以在qt.pro裏面添加,也可以在main.h裏面添加。
DEFINES += MEMWATCH
最後是在程序執行地方調用
mwInit();
結束地方調用
mwTerm();
建議看壓縮包裏面 的USING文檔。
動態庫的顯式調用
在windows平臺調用方法。
https://blog.csdn.net/Hilavergil/article/details/78544424
總結如下
typedef double(SQRTPROC)(double); HINSTANCE hInstance;
SQRTPROC* pFunction;
VERIFY(hInstance=::LoadLibrary("c:\\winnt\\system32\\mydll.dll"));
VERIFY(pFunction=(SQRTPROC*)::GetProcAddress(hInstance,"SquareRoot"));
double d=(*pFunction)(81.0);//調⽤用該DLL函數
在linux mac平臺下的調用方法
https://blog.csdn.net/lc_910927/article/details/42393121
總結幾句
1.導入
#include <dlfcn.h>
2.其次,編譯的時候導入-ldl庫即libdl.dylib (mac)或者 libdl.so(linux)
#LIBS += -ldl
//打開動態庫
void *hand = dlopen(fullpath,RTLD_NOW);
//定義函數指針
typedef void (*SAYMYNAME)();
//從handler 裏面獲得函數地址,並且轉化成函數指針
SAYMYNAME p1=(SAYMYNAME)dlsym(hand,"sayMyName");
//執行函數調用
p1();
//關閉
dlclose(hand);
//查錯
char err=dlerror();