C語言部分復習筆記

1. 指針和數組

數組指針 和 指針數組

?int* p1[10]; // 指針數組int (*p2)[10]; // 數組指針

因為 [] 的優先級比 * 高,p先和 [] 結合說明p是一個數組,p先和*結合說明p是一個指針

括號保證p先和*結合,說明p是一個指針變量,然后指著指向的是一個大小為10個整型的數組。所以p是一個 指針,指向一個數組,叫數組指針。

arr和&arr的區別

arr代表數組首元素的地址,&arr代表整個數組的地址

?void test(int(*arr)[10], int size) // 這里arr也是整個數組的數組指針{for (int i = 0; i < size; ++i){cout << ((int*)arr)[i] << " ";}cout << endl;}?int main(){int arr[10] = { 0 };int(*p)[10] = &arr; // 數組指針需要指整個數組test(p, 10);return 0;}

二維數組傳參

?
void test(int arr[3][5])//ok?{}void test(int arr[][])//ok? X{}void test(int arr[][5])//ok?{}// 總結:二維數組傳參,函數形參的設計只能省略第一個[]的數字。// 因為對一個二維數組,可以不知道有多少行,但是必須知道一行多少元素。這樣才方便運算。void test(int* arr)//ok?X{}void test(int* arr[5])//ok?{}void test(int(*arr)[5])//ok?arr是指向一個大小為5的一維數組{}void test(int** arr)//ok?{}int main(){int arr[3][5] = { 0 };test(arr);}

函數指針

保存函數的地址:函數指針

?#include <stdio.h>void test(){}?int main(){printf("%p\n", test);printf("%p\n", &test); // 一樣cout << typeid(test).name() << endl; // void __cdecl(void) 函數名cout << typeid(&test).name() << endl; // void (__cdecl*)(void) 函數指針void(*p1)(void) = test;void(*p2)(void) = &test; // 一樣的return 0;}

函數指針數組

?typedef void(*handler)(void);?int main(){handler arr[12] = { 0 };void(*arr1[12])(void) ?= { 0 };}

const和指針

const修飾的指針變量:

  1. const位于*前的,表示指針指向的對象內容無法修改,p指向的空間內容(指向對象的內容)無法修改

  2. const位于*后面的,表示指針指向的位置無法修改,p的內容(保存的對象地址)無法修改

?    const int* p = nullptr;int const* p = nullptr;int* const p = nullptr;

sizeof和指針,數組/strlen和指針,數組

sizeof是根據對象的類型判斷大小,但是有一個特殊處理就是數組名,sizeof(數組名)

  1. sizeof(數組名),這里的數組名表示整個數組,計算的是整個數組的大小

  2. &數組名,這里的數組名表示整個數組,取出的是整個數組的地址

  3. 除此之外所有的數組名都表示首元素的地址

  4. 但是參數數組也是一個特殊的存在,當數組作為參數進行傳遞的時候,數組其實退化成了指針

?//一維數組int a[] = {1,2,3,4};printf("%d\n",sizeof(a));       // 16printf("%d\n",sizeof(a+0));     // 4/8printf("%d\n",sizeof(*a));      // 4 printf("%d\n",sizeof(a+1));     // 4/8printf("%d\n",sizeof(a[1]));    // 4printf("%d\n",sizeof(&a));      // 4/8printf("%d\n",sizeof(*&a));     // 16(*和&抵消了)printf("%d\n",sizeof(&a+1));    // 4/8printf("%d\n",sizeof(&a[0]));   // 4/8printf("%d\n",sizeof(&a[0]+1)); // 4/8// 字符數組char arr[] = {'a','b','c','d','e','f'}; // 6個 系統不會給最后補0 ""這樣賦值才行printf("%d\n", sizeof(arr));        // 6printf("%d\n", sizeof(arr+0));      // 4/8printf("%d\n", sizeof(*arr));       // 1printf("%d\n", sizeof(arr[1]));     // 1printf("%d\n", sizeof(&arr));       // 4/8printf("%d\n", sizeof(&arr+1));     // 4/8printf("%d\n", sizeof(&arr[0]+1));  // 4/8printf("%d\n", strlen(arr));        // 未知printf("%d\n", strlen(arr+0));      // 未知printf("%d\n", strlen(*arr));       // 錯誤printf("%d\n", strlen(arr[1]));     // 錯誤printf("%d\n", strlen(&arr));       // 報錯printf("%d\n", strlen(&arr+1));     // 報錯,因為&arr的類型char(*)[6]printf("%d\n", strlen(&arr[0]+1));  // 未知 優先級 [] > * > &char arr[] = "abcdef";  // 7個 最后補0printf("%d\n", sizeof(arr));        // 7printf("%d\n", sizeof(arr+0));      // 4/8printf("%d\n", sizeof(*arr));       // 1printf("%d\n", sizeof(arr[1]));     // 1printf("%d\n", sizeof(&arr));       // 4/8printf("%d\n", sizeof(&arr+1));     // 4/8printf("%d\n", sizeof(&arr[0]+1));  // 4/8printf("%d\n", strlen(arr));        // 6printf("%d\n", strlen(arr+0));      // 6printf("%d\n", strlen(*arr));       // 報錯printf("%d\n", strlen(arr[1]));     // 報錯printf("%d\n", strlen(&arr));       // 報錯printf("%d\n", strlen(&arr+1));     // 報錯printf("%d\n", strlen(&arr[0]+1));  // 5const char *p = "abcdef"; // 最后會補'\0'printf("%d\n", sizeof(p));          // 4/8printf("%d\n", sizeof(p+1));        // 4/8printf("%d\n", sizeof(*p));         // 1printf("%d\n", sizeof(p[0]));       // 1printf("%d\n", sizeof(&p));         // 4/8printf("%d\n", sizeof(&p+1));       // 4/8printf("%d\n", sizeof(&p[0]+1));    // 4/8printf("%d\n", strlen(p));          // 6printf("%d\n", strlen(p+1));        // 5printf("%d\n", strlen(*p));         // 報錯printf("%d\n", strlen(p[0]));       // 報錯printf("%d\n", strlen(&p));         // 報錯printf("%d\n", strlen(&p+1));       // 報錯printf("%d\n", strlen(&p[0]+1));    // 5?//二維數組int a[3][4] = {0};printf("%d\n",sizeof(a));           // 48printf("%d\n",sizeof(a[0][0]));     // 4printf("%d\n",sizeof(a[0]));        // 16printf("%d\n",sizeof(a[0]+1));      // 4/8 (指針) a[0][1]// 這里a[0] 表示a的首個元素,因為sizeof的特殊所以被當成整個數組大小 +1 后這個特殊就沒了printf("%d\n",sizeof(*(a[0]+1)));   // 4printf("%d\n",sizeof(a+1));         // 4/8printf("%d\n",sizeof(*(a+1)));      // 4/8X  16 a[1]printf("%d\n",sizeof(&a[0]+1));     // 4/8 printf("%d\n",sizeof(*(&a[0]+1)));  // 4X  16 ? a[1]printf("%d\n",sizeof(*a));          // 4/8X  16 a[0]printf("%d\n",sizeof(a[3]));        // 4/8X  16

總結:先看類型再判斷

2. 庫函數的模擬實現

memcpy

?void* memcpy(void* dest, const void* src, size_t num){assert(dest && src);char* d = (char*)dest;const char* s = (const char*)src;while (num--){*d++ = *s++;}return dest;}

注意:c++使用括號強轉類型,生成的是臨時變量,不能進行++

memmove

?void* memmove(void* dest, const void* src, size_t num){assert(dest && src);char* d = static_cast<char*>(dest);const char* s = static_cast<const char*>(src);while (num--){if (dest < src){*d++ = *s++;}else{*((char*)(d + num)) = *(s + num); // 這里根據num的減少來推進}}return dest;}

strstr

?// 從目的字符串中找src字符串static char* strstr(const char* dest, const char* src){assert(dest && src);const char* left = dest, * right = dest;const char* cur = src;while (true){while (*left != '\0' && *left != *cur) left++;if (*left == '\0')break;// *left == *curright = left;while (*right == *cur){right++;cur++;if (*cur == '\0')return const_cast<char*>(left);}cur = src; // cur 回執left++;}return nullptr;}

memset/strcmp

?void* memset(void* ptr, int val, size_t num){assert(ptr);char* cur = static_cast<char*>(ptr);while (num--){*cur++ = val;}return ptr;}int strcmp(const char* str1, const char* str2){assert(str1 && str2);while (*str1 != '\0' && *str2 != '\0' && *str1++ == *str2++);//if (*str1 < *str2)//  return -1;//else if (*str1 > *str2)//  return 1;//else return 0;return *str1 - *str2;}

3. 自定義類型

內存對齊規則

  1. 第一個成員在與結構體變量偏移量為0的地址處。

  2. 其他成員變量要對齊到某個數字(對齊數)的整數倍的地址處

  3. 結構體總大小為最大對齊數(每個成員變量都有一個對齊數)的整數倍

  4. 如果嵌套了結構體的情況,嵌套的結構體對齊到自己的最大對齊數的整數倍處,結構體的整體大小就是所有最大對齊數(含嵌套結構體的對齊數)的整數倍

對齊數 = 編譯器默認的一個對齊數(VS下是8) 與 該成員大小的較小值

聯合體

聯合也是一種特殊的自定義類型 這種類型定義的變量也包含一系列的成員,特征是這些成員公用同一塊空間(所以聯合也叫共用體)

聯合的成員是共用同一塊內存空間的,這樣一個聯合變量的大小,至少是最大成員的大小(因為 聯合至少得有能力保存最大的那個成員)

聯合大小的計算:

聯合的大小至少是最大成員的大小,當最大成員大小不是最大對齊數的整數倍的時候,就要對齊到最大對齊數的整數倍

4. 整形的存儲規則

原碼/反碼/補碼

計算機中的有符號數有三種表示方法,即原碼、反碼和補碼

三種表示方法均有符號位和數值位兩部分,符號位都是用0表示“正”,用1表示“負”,而數值位三種表示方法各不相同

  • 原碼:直接將二進制按照正負數的形式翻譯成二進制就可以

  • 反碼: 將原碼的符號位不變,其他位依次按位取反就可以得到了

  • 補碼: 反碼+1就得到補碼

正數的原、反、補碼都相同

對于整形來說:數據存放內存中其實存放的是補碼

大小端

大端(存儲)模式,是指數據的低位保存在內存的高地址中,而數據的高位,保存在內存的低地址中(高低)

小端(存儲)模式,是指數據的低位保存在內存的低地址中,而數據的高位,保存在內存的高地址中(高高)

如何判斷:

?#include <stdio.h>int check_sys(){int i = 1;return (*(char *)&i);}int main(){int ret = check_sys();if(ret == 1)printf("小端\n");elserintf("大端\n");return 0;}//代碼2int check_sys(){union{int i;char c;}un;un.i = 1;return un.c;}

5. 編譯鏈接

#define 替換規則 在程序中擴展#define定義符號和宏時,需要涉及幾個步驟:

  1. 在調用宏時,首先對參數進行檢查,看看是否包含任何由#define定義的符號。如果是,它們首先被替換。

  2. 替換文本隨后被插入到程序中原來文本的位置。對于宏,參數名被他們的值替換。

  3. 最后,再次對結果文件進行掃描,看看它是否包含任何由#define定義的符號。如果是,就重復上述處理過程。

注意:

  1. 宏參數和#define 定義中可以出現其他#define定義的變量。但是對于宏,不能出現遞歸

  2. 當預處理器搜索#define定義的符號的時候,字符串常量的內容并不被搜索

也就是說"宏"只會被當成字符串,宏不會生效,這時#宏:把一個宏參數變成對應的字符串

?#include <stdio.h>?#define PRINT1(FORMAT, VALUE) \printf("the value is "FORMAT"\n", VALUE)?#define PRINT2(FORMAT, VALUE) \printf("the value of "#VALUE" is "FORMAT"\n", VALUE) // yes//printf("the value of ""VALUE"" is "FORMAT"\n", VALUE) // no?int main(){char a = -1;signed char b = -1;unsigned char c = -1;printf("a=%d,b=%d,c=%d\n", a, b, c); // 對齊 -1 -1 255printf("file:%s\n line:%d\n time:%s\n", __FILE__, __LINE__, __TIME__);const char* p = "hello ""bit\n"; // 字符串合并printf("%s\n", p);PRINT1("%d", 10);PRINT2("%d", 10);return 0;}

可以把位于它兩邊的符號合成一個符號。 它允許宏定義從分離的文本片段創建標識符

?#define OFFSETOF(struct_name, member_name) \((size_t)&(((struct_name*)0)->member_name))// 獲取成員變量的偏移量

宏的優缺點:

優點

  1. 用于調用函數和從函數返回的代碼可能比實際執行這個小型計算工作所需要的時間更多。所以宏比函數在程序 的規模和速度方面更勝一籌。

  2. 更為重要的是函數的參數必須聲明為特定的類型。所以函數只能在類型合適的表達式上使用。反之這個宏怎可 以適用于整形、長整型、浮點型等可以用于>來比較的類型。宏是類型無關的。(C++模板)

缺點

  1. 每次使用宏的時候,一份宏定義的代碼將插入到程序中。除非宏比較短,否則可能大幅度增加程序的長度

  2. 宏是沒法調試的。

  3. 宏由于類型無關,也就不夠嚴謹

  4. 宏可能會帶來運算符優先級的問題,導致程序容易出現錯

#undef 于移除一個宏定義

?gcc -D ARRAY_SIZE=10 programe.c // 命令行宏定義

條件編譯

?#if defined(OS_UNIX) #ifdef OPTION1 unix_version_option1(); #elif defined(OPTION2)unix_version_option2(); #elseunix_version_option3(); #endif #elif defined(OS_MSDOS) #ifdef OPTION2 msdos_version_option2(); #endif #endif

編譯鏈接過程

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/diannao/38850.shtml
繁體地址,請注明出處:http://hk.pswp.cn/diannao/38850.shtml
英文地址,請注明出處:http://en.pswp.cn/diannao/38850.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

Web2Code :網頁理解和代碼生成能力的評估框架

多模態大型語言模型&#xff08;MLLMs&#xff09;在過去幾年中取得了爆炸性的增長。利用大型語言模型&#xff08;LLMs&#xff09;中豐富的常識知識&#xff0c;MLLMs在處理和推理各種模態&#xff08;如圖像、視頻和音頻&#xff09;方面表現出色&#xff0c;涵蓋了識別、推…

系統中非功能性需求的思考

概要 設計系統時不僅要考慮功能性需求&#xff0c;還要考慮一些非功能性需求&#xff0c;比如&#xff1a; 擴展性可靠性和冗余安全和隱私服務依賴SLA要求 下面對這5項需要考慮的事項做個簡單的說明 1. 可擴展性 數據量增長如何擴展&#xff1f; 流量增長如何擴展&#xf…

【LLM教程-llama】如何Fine Tuning大語言模型?

今天給大家帶來了一篇超級詳細的教程,手把手教你如何對大語言模型進行微調(Fine Tuning)&#xff01;&#xff08;代碼和詳細解釋放在后文&#xff09; 目錄 大語言模型進行微調(Fine Tuning)需要哪些步驟&#xff1f; 大語言模型進行微調(Fine Tuning)訓練過程及代碼 大語言…

VuePress介紹

從本文開始&#xff0c;動手搭建自己的博客&#xff01;希望讀者能跟著一起動手&#xff0c;這樣才能真正掌握。 ? VuePress 是什么 VuePress 是由 Vue 作者帶領團隊開發的&#xff0c;非常火&#xff0c;使用的人很多&#xff1b;Vue 框架官網也是用了 VuePress 搭建的。即…

000.二分查找算法題解目錄

000.二分查找算法題解目錄 69. x 的平方根&#xff08;簡單&#xff09;

4PCS點云配準算法實現

4PCS點云配準算法的C實現如下&#xff1a; #include <iostream> #include <pcl/io/pcd_io.h> #include <pcl/point_types.h> #include <pcl/common/common.h> #include <pcl/common/distances.h> #include <pcl/common/transforms.h> #in…

唯一ID:UUID 介紹與 google/uuid 庫生成 UUID

UUID 即通用唯一識別碼&#xff0c;是一種用于計算機系統中以確保全局唯一性的標識符。其標準定義于 RFC 4122 文檔中。標準形式包含 32 個 16 進制數字&#xff0c;以連字符切割為五組&#xff0c;格式為 8-4-4-4-12&#xff0c;總共 36 個字符。&#xff08;形如, d169aa7f-4…

php 通過vendor文件 生成還原最新的composer.json

起因&#xff1a;因為歷史原因&#xff0c;在本項目中composer.json基本算廢了&#xff0c;沒法直接使用composer管理擴展&#xff0c;今天嘗試修復一下composer.json。 歷史文件&#xff0c;可以看出來已經很久沒有維護了&#xff0c;我們主要是恢復require的信息 {"na…

K8s節點維護流程

用途 用于下線異常節點、集群縮容等 操作步驟 1. 查看節點名稱 先確認節點的名稱 kubectl get node -o wide2. 設置節點不可調度 設置節點不可調度狀態&#xff0c;禁止新的pod調度到該節點上 kubectl cordon ${node_name}3. 剔除節點上運行的pod&#xff08;生產環境慎…

Spring Boot中集成Redis實現緩存功能

Spring Boot中集成Redis實現緩存功能 大家好&#xff0c;我是免費搭建查券返利機器人省錢賺傭金就用微賺淘客系統3.0的小編&#xff0c;也是冬天不穿秋褲&#xff0c;天冷也要風度的程序猿&#xff01;今天我們將深入探討如何在Spring Boot應用程序中集成Redis&#xff0c;實現…

AP無法上線原因分析及排障

一、AP未分配到IP地址 如果遇到AP無法上線問題&#xff0c;可以檢查下AP是否分配到IP地址。AP獲取IP地址有兩種方式&#xff1a;靜態方式&#xff1a;登錄到AP設備&#xff0c;手工配置IP地址&#xff0c;該方式操作起來比較麻煩&#xff0c;不推薦使用&#xff1b;DHCP方式&am…

基于CNN的股票預測方法【卷積神經網絡】

基于機器學習方法的股票預測系列文章目錄 一、基于強化學習DQN的股票預測【股票交易】 二、基于CNN的股票預測方法【卷積神經網絡】 文章目錄 基于機器學習方法的股票預測系列文章目錄一、CNN建模原理二、模型搭建三、模型參數的選擇&#xff08;1&#xff09;探究window_size…

下代iPhone或回歸可拆卸電池,蘋果這操作把我看傻了

剛度過一個愉快的周末&#xff0c;蘋果又雙叒叕攤上事兒了。 iPhone13 系列被曝扎堆電池鼓包了。 早在去年&#xff0c;就有 iPhone13 和 iPhone14 用戶反饋過類似的問題&#xff0c;表示在手機僅僅使用了一年多的時間就出現了電池鼓包的情況&#xff0c;而且還把屏幕給撐起來了…

舞會無領導:一種樹形動態規劃的視角

沒有上司的舞會 Ural 大學有 &#x1d441; 名職員&#xff0c;編號為1~&#x1d441;。 他們的關系就像一棵以校長為根的樹&#xff0c;父節點就是子節點的直接上司。 每個職員有一個快樂指數&#xff0c;用整數 &#x1d43b;&#x1d456; 給出&#xff0c;其中1≤&…

校園卡手機卡怎么注銷?

校園手機卡的注銷流程可以根據不同的運營商和具體情況有所不同&#xff0c;但一般來說&#xff0c;以下是注銷校園手機卡的幾種常見方式&#xff0c;我將以分點的方式詳細解釋&#xff1a; 一、線上注銷&#xff08;通過手機APP或官方網站&#xff09; 下載并打開對應運營商的…

C++ 指針介紹

指針是C編程語言中的一個強大且重要的特性。它允許程序員直接操作內存地址&#xff0c;從而提供了對低級別內存的訪問和控制。雖然指針在使用時可能比較復雜且容易出錯&#xff0c;但它們在提高程序效率和靈活性方面有著不可替代的作用。本文將介紹C指針的基本概念、用法及其應…

Docker 中 MySQL 遷移策略(單節點)

目錄 一、 簡介二、操作流程2.1 進入mysql容器2.2 導出 MySQL 數據2.3. 將導出的文件復制到宿主機2.4 創建 Docker Compose 配置2.5 啟動新的 Docker 容器2.6 導入數據到新的容器2.7 驗證數據2.8 刪除舊的容器&#xff08;刪除操作需慎重&#xff09; 三、推薦配置四、寫在后面…

當年很多跑到美加澳寫代碼的人現在又移回香港?什么原因?

當年很多跑到美加澳寫代碼的人現在又移回香港&#xff1f;什么原因&#xff1f; 近年來&#xff0c;確實有部分曾經移民到美國、加拿大、澳大利亞等地的香港居民選擇移回香港。這一現象與多種因素相關&#xff0c;主要可以歸結為以下幾點&#xff1a; 疫情后的環境變化&#…

【STM32】溫濕度采集與OLED顯示

一、任務要求 1. 學習I2C總線通信協議&#xff0c;使用STM32F103完成基于I2C協議的AHT20溫濕度傳感器的數據采集&#xff0c;并將采集的溫度-濕度值通過串口輸出。 任務要求&#xff1a; 1&#xff09;解釋什么是“軟件I2C”和“硬件I2C”&#xff1f;&#xff08;閱讀野火配…

2025第13屆常州國際工業裝備博覽會招商全面啟動

常州智造 裝備中國|2025第13屆常州國際工業裝備博覽會招商全面啟動 2025第13屆常州國際工業裝備博覽會將于2025年4月11-13日在常州西太湖國際博覽中心盛大舉行&#xff01;目前&#xff0c;各項籌備工作正穩步推進。 60000平米的超大規模、800多家國內外工業裝備制造名企將云集…