C語言常見重要結論。

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();


發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章