97色伦色在线综合视频,无玛专区,18videosex性欧美黑色,日韩黄色电影免费在线观看,国产精品伦理一区二区三区,在线视频欧美日韩,亚洲欧美在线中文字幕不卡

給別人做的網(wǎng)站要復(fù)雜做安全掃描鄭州東站附近網(wǎng)站建設(shè)公司

鶴壁市浩天電氣有限公司 2026/01/24 03:34:30
給別人做的網(wǎng)站要復(fù)雜做安全掃描,鄭州東站附近網(wǎng)站建設(shè)公司,中國(guó)建設(shè)銀行老版本下載官方網(wǎng)站,做與食品安全有關(guān)的網(wǎng)站在過(guò)去的幾周里#xff0c;我們討論過(guò)圖像是由更小的構(gòu)建單元——像素——組成的。 本周#xff0c;我們將#xff1a; 深入探討構(gòu)成圖像的二進(jìn)制數(shù)據(jù)研究文件在內(nèi)存中的存儲(chǔ)方式學(xué)習(xí)如何直接訪問(wèn)和操作計(jì)算機(jī)內(nèi)存中的數(shù)據(jù)掌握C語(yǔ)言中的指針概念 重要提示#xff1a;本周…在過(guò)去的幾周里我們討論過(guò)圖像是由更小的構(gòu)建單元——像素——組成的。本周我們將深入探討構(gòu)成圖像的二進(jìn)制數(shù)據(jù)研究文件在內(nèi)存中的存儲(chǔ)方式學(xué)習(xí)如何直接訪問(wèn)和操作計(jì)算機(jī)內(nèi)存中的數(shù)據(jù)掌握C語(yǔ)言中的指針概念重要提示本周的內(nèi)容可能是整個(gè)課程中最具挑戰(zhàn)性的部分之一。涉及的概念特別是指針需要時(shí)間消化和理解這是完全正常的。不要?dú)怵H慢慢來(lái)像素Pixels什么是像素像素Pixel是圖像的最小單位是排列在上下、左右網(wǎng)格上的方形色點(diǎn)。簡(jiǎn)單理解像素 Picture Element圖片元素每個(gè)像素都是一個(gè)獨(dú)立的彩色點(diǎn)成千上萬(wàn)的像素組成了我們看到的圖像黑白圖像最簡(jiǎn)單的圖像是黑白圖像可以用位圖bitmap表示0代表黑色1代表白色通過(guò)排列0和1就能創(chuàng)建簡(jiǎn)單的圖案和圖像十六進(jìn)制HexadecimalRGB顏色模型彩色圖像使用RGBRed, Green, Blue顏色模型每種顏色由三個(gè)數(shù)值組成R紅色、G綠色、B藍(lán)色每個(gè)值的范圍0 到 255在Adobe Photoshop中RGB設(shè)置如下所示示例純紅色RGB(255, 0, 0)純綠色RGB(0, 255, 0)純藍(lán)色RGB(0, 0, 255)白色RGB(255, 255, 255)黑色RGB(0, 0, 0)問(wèn)題為什么用十六進(jìn)制注意圖片底部有個(gè)特殊值#FFFFFF疑問(wèn)為什么255被表示成FF這就引出了十六進(jìn)制的概念十六進(jìn)制基礎(chǔ)十六進(jìn)制Hexadecimal是一種以16為基數(shù)的計(jì)數(shù)系統(tǒng)也叫base-16。十六進(jìn)制的數(shù)字十六進(jìn)制使用16個(gè)符號(hào)0 1 2 3 4 5 6 7 8 9 A B C D E F十六進(jìn)制十進(jìn)制0011......99A10B11C12D13E14F15數(shù)字表示對(duì)比十進(jìn)制二進(jìn)制十六進(jìn)制000000100011910019101010A151111F16100001025511111111FF為什么255是FF計(jì)算過(guò)程FF (十六進(jìn)制) F × 161 F × 16? 15 × 16 15 × 1 240 15 255 (十進(jìn)制)位值理解十六進(jìn)制的每一位代表16的某次方右邊第一位16? 1右邊第二位161 16右邊第三位162 256...為什么使用十六進(jìn)制優(yōu)勢(shì)1簡(jiǎn)潔對(duì)比二進(jìn)制11111111(8位)十六進(jìn)制FF(2位)用更少的字符表示相同的值優(yōu)勢(shì)2與二進(jìn)制的完美對(duì)應(yīng)關(guān)鍵1個(gè)十六進(jìn)制位 4個(gè)二進(jìn)制位二進(jìn)制 1111 1111 十六進(jìn)制 F F這讓程序員在二進(jìn)制和十六進(jìn)制之間轉(zhuǎn)換非常方便優(yōu)勢(shì)3表示內(nèi)存地址計(jì)算機(jī)內(nèi)存地址通常用十六進(jìn)制表示0x前綴表示十六進(jìn)制數(shù)示例0xFF、0x1A2B、0x7FFFRGB顏色的十六進(jìn)制表示純紅色#FF0000 RGB(255, 0, 0)純綠色#00FF00 RGB(0, 255, 0)白色#FFFFFF RGB(255, 255, 255)黑色#000000 RGB(0, 0, 0)每?jī)晌皇M(jìn)制數(shù)代表一個(gè)0-255的顏色分量?jī)?nèi)存Memory內(nèi)存的可視化回顧之前的課程我們把內(nèi)存想象成一排連續(xù)的格子?,F(xiàn)在讓我們用十六進(jìn)制來(lái)標(biāo)記這些內(nèi)存位置問(wèn)題看到10這個(gè)格子它是內(nèi)存地址10還是存儲(chǔ)的值10容易混淆0x 前綴為了避免混淆約定所有十六進(jìn)制數(shù)都加上0x前綴現(xiàn)在0x10明確表示十六進(jìn)制的10等于十進(jìn)制的1610默認(rèn)是十進(jìn)制的10示例0x0 00xF 150x10 160xFF 2550x100 256地址與指針Addresses Pointers這是C語(yǔ)言中最強(qiáng)大但也最容易讓人困惑的概念。讓我們放慢速度一步步拆解。兩個(gè)關(guān)鍵運(yùn)算符在C語(yǔ)言中有兩個(gè)與內(nèi)存直接相關(guān)的魔法運(yùn)算符1. 取地址運(yùn)算符(Ampersand)作用獲取某個(gè)變量在內(nèi)存中的地址口訣在這個(gè)變量在什么地方2. 解引用運(yùn)算符*(Asterisk)作用訪問(wèn)某個(gè)地址指向的內(nèi)容口訣去這個(gè)地址看看里面有什么實(shí)踐獲取變量的地址讓我們看一段簡(jiǎn)單的代碼// addresses.c #include stdio.h int main(void) { int n 50; printf(%i , n); }這段代碼會(huì)在內(nèi)存中開辟一個(gè)空間4個(gè)字節(jié)來(lái)存儲(chǔ)整數(shù)50。問(wèn)題這個(gè)變量n具體在內(nèi)存的哪個(gè)位置門牌號(hào)我們可以修改代碼來(lái)打印它的地址#include stdio.h int main(void) { int n 50; // %p 是專門用來(lái)打印指針/地址的格式符 (pointer) // n 表示 獲取變量 n 的地址 printf(%p , n); }運(yùn)行結(jié)果示例0x7ffda0a476fc這是一個(gè)十六進(jìn)制數(shù)代表了n在計(jì)算機(jī)內(nèi)存中的具體位置。什么是指針指針Pointer其實(shí)非常簡(jiǎn)單它就是一個(gè)專門用來(lái)存儲(chǔ)內(nèi)存地址的變量。普通變量如int n存儲(chǔ)的是數(shù)據(jù)如 50。指針變量如int *p存儲(chǔ)的是地址如 0x7ffda0a476fc。定義指針int n 50; int *p n;這行代碼int *p n;發(fā)生了什么int *p定義了一個(gè)指針變量名字叫p。int *表示這個(gè)指針是專門用來(lái)存int類型變量的地址的。n獲取了變量n的地址。把n的地址賦值給p。結(jié)論現(xiàn)在p 指向了 n??梢暬斫庀胂髢?nèi)存是一個(gè)巨大的儲(chǔ)物柜n是一個(gè)柜子里面放著數(shù)字50。p是另一個(gè)柜子里面放著一張紙條紙條上寫著n那個(gè)柜子的編號(hào)。使用指針訪問(wèn)數(shù)據(jù)既然p存了n的地址我們就可以通過(guò)p找到n。#include stdio.h int main(void) { int n 50; int *p n; // p 指向 n // 打印 p 存儲(chǔ)的地址 printf(%p , p); // 打印 p 指向的地址里的值 (即 n 的值) // *p 的意思是去 p 記錄的地址看看那里存了什么 printf(%i , *p); }輸出0x7ffda0a476fc 50總結(jié)p是地址。*p是該地址處的值。字符串的真相Strings are PointersCS50庫(kù)的謊言在之前的課程中我們使用string類型來(lái)定義字符串string s HI!;但其實(shí)C語(yǔ)言原生并沒有string這個(gè)類型這只是CS50庫(kù)為了方便初學(xué)者而定義的一個(gè)別名typedef。字符串到底是什么字符串本質(zhì)上是字符數(shù)組而所謂的string變量實(shí)際上是一個(gè)指向該字符數(shù)組第一個(gè)字符的指針。讓我們揭開面紗#include stdio.h int main(void) { // 不用 cs50.h 庫(kù)使用 C 語(yǔ)言原生的寫法 char *s HI!; printf(%s , s); }詳細(xì)解析char *s HI!;內(nèi)存中分配了一塊連續(xù)空間存儲(chǔ)字符H,I,!,。s是一個(gè)指針類型是char *指向字符的指針。s存儲(chǔ)了第一個(gè)字符H的地址。驗(yàn)證字符串就是指針我們可以打印出字符串中每個(gè)字符的地址來(lái)驗(yàn)證#include stdio.h int main(void) { char *s HI!; // 打印 s 本身它存儲(chǔ)的是 H 的地址 printf(s: %p , s); // 打印每個(gè)字符的地址 printf(s[0]: %p , s[0]); printf(s[1]: %p , s[1]); printf(s[2]: %p , s[2]); printf(s[3]: %p , s[3]); }輸出示例s: 0x402004 s[0]: 0x402004 -- 注意s 和 s[0] 是一樣的 s[1]: 0x402005 s[2]: 0x402006 s[3]: 0x402007關(guān)鍵發(fā)現(xiàn)s的值就是第一個(gè)字符s[0]的地址。字符在內(nèi)存中是連續(xù)存儲(chǔ)的地址每次1。指針?biāo)阈g(shù)Pointer Arithmetic既然指針存儲(chǔ)的是數(shù)字地址我們自然可以對(duì)它進(jìn)行數(shù)學(xué)運(yùn)算訪問(wèn)字符串的另一種方式通常我們用s[0],s[1]來(lái)訪問(wèn)字符。但在底層編譯器是這樣理解的s[0]等同于*s去 s 指向的地址取值s[1]等同于*(s 1)去 s 的下一個(gè)地址取值s[2]等同于*(s 2)去 s 的下下個(gè)地址取值#include stdio.h int main(void) { char *s HI!; // 數(shù)組下標(biāo)方式 printf(%c , s[0]); printf(%c , s[1]); printf(%c , s[2]); // 指針?biāo)阈g(shù)方式 printf(%c , *s); printf(%c , *(s 1)); printf(%c , *(s 2)); }這兩種寫法效果完全一樣*(s1)的意思是取出 s 里的地址加上 1 個(gè)單位這里是 1 個(gè)字節(jié)然后去那個(gè)新地址看看里面有什么。字符串比較的陷阱回顧之前的疑問(wèn)為什么不能用比較兩個(gè)字符串char *s get_string(s: ); // 假設(shè)輸入 HI! char *t get_string(t: ); // 假設(shè)輸入 HI! if (s t) ... // 結(jié)果是 Different原因分析因?yàn)閟和t是指針s存儲(chǔ)的是第一個(gè) HI! 在內(nèi)存中的地址比如 0x123。t存儲(chǔ)的是第二個(gè) HI! 在內(nèi)存中的地址比如 0x456。s t比較的是地址是否相同。因?yàn)樗鼈兇鎯?chǔ)在內(nèi)存的不同位置地址肯定不同所以結(jié)果是false。正確做法使用strcmp(s, t)它會(huì)去這兩個(gè)地址逐個(gè)字符比較里面的內(nèi)容。字符串復(fù)制與內(nèi)存分配malloc如果我們想復(fù)制一個(gè)字符串簡(jiǎn)單的賦值是不行的string s get_string(s: ); string t s; // 錯(cuò)誤這只是復(fù)制了指針地址這樣做之后t和s指向同一個(gè)內(nèi)存地址。如果你修改t[0]s[0]也會(huì)跟著變這稱為淺拷貝Shallow Copy。真正的復(fù)制深拷貝要制作一個(gè)真正的副本我們需要向計(jì)算機(jī)申請(qǐng)一塊新的內(nèi)存空間。把s里的字符一個(gè)個(gè)復(fù)制到新空間里。我們使用兩個(gè)新函數(shù)malloc(size)Memory Allocation向系統(tǒng)申請(qǐng)指定大小的內(nèi)存。free(pointer)釋放之前申請(qǐng)的內(nèi)存用完必須還。#include cs50.h #include ctype.h #include stdio.h #include stdlib.h // malloc 和 free 在這里 #include string.h int main(void) { char *s get_string(s: ); if (s NULL) return 1; // 安全檢查 // 1. 申請(qǐng)內(nèi)存 // strlen(s) 1 是為了給結(jié)尾的 留位置 char *t malloc(strlen(s) 1); if (t NULL) return 1; // 申請(qǐng)失敗檢查 // 2. 復(fù)制字符 // strcpy(t, s) 是標(biāo)準(zhǔn)庫(kù)函數(shù)相當(dāng)于寫了一個(gè)循環(huán) strcpy(t, s); // 3. 修改副本 if (strlen(t) 0) { t[0] toupper(t[0]); } // 4. 打印結(jié)果 printf(s: %s , s); // 原始字符串不變 printf(t: %s , t); // 副本首字母變大寫 // 5. 釋放內(nèi)存 free(t); return 0; }重要原則有借有還再借不難。每一個(gè)malloc都必須對(duì)應(yīng)一個(gè)free否則會(huì)導(dǎo)致內(nèi)存泄漏Memory Leak。垃圾值Garbage Values什么是垃圾值當(dāng)你向計(jì)算機(jī)申請(qǐng)一塊內(nèi)存例如定義一個(gè)數(shù)組時(shí)你得到的內(nèi)存不一定是空的。int scores[1024]; // 申請(qǐng)了1024個(gè)int的空間這塊內(nèi)存之前可能被其他程序使用過(guò)里面殘留著舊數(shù)據(jù)比如 848, 1927100, -42 等。這些毫無(wú)意義的舊數(shù)據(jù)被稱為垃圾值。演示垃圾值// garbage.c #include stdio.h #include stdlib.h int main(void) { int scores[1024]; // 注意我們沒有初始化數(shù)組沒有賦值 for (int i 0; i 1024; i) { printf(%i , scores[i]); } }運(yùn)行結(jié)果示例4 848 0 1927100 ...教訓(xùn)永遠(yuǎn)不要假設(shè)未初始化的變量是0定義變量后最好立即給它賦初值。內(nèi)存交換Swapping這是一個(gè)經(jīng)典的面試題如何交換兩個(gè)變量的值錯(cuò)誤嘗試值傳遞Pass by Value#include stdio.h void swap(int a, int b); int main(void) { int x 1; int y 2; printf(Before swap: x%i, y%i , x, y); swap(x, y); printf(After swap: x%i, y%i , x, y); } void swap(int a, int b) { int tmp a; a b; b tmp; }結(jié)果x和y的值沒有變?cè)駽語(yǔ)言函數(shù)調(diào)用默認(rèn)是傳值Pass by Value。main函數(shù)把x的副本傳給了swap。swap里的a和b只是局部變量它們交換了但完全沒影響到main里的x和y。正確做法引用傳遞Pass by Reference如果我們想改變main里的變量必須告訴swap函數(shù)這些變量的地址。#include stdio.h // 接收兩個(gè)整數(shù)的地址指針 void swap(int *a, int *b); int main(void) { int x 1; int y 2; printf(Before swap: x%i, y%i , x, y); // 傳遞 x 和 y 的地址 swap(x, y); printf(After swap: x%i, y%i , x, y); } void swap(int *a, int *b) { // *a 意味著去地址 a 看看把那里的值取出來(lái) int tmp *a; // 把地址 b 里的值賦給地址 a 指向的位置 *a *b; // 把 tmp 的值賦給地址 b 指向的位置 *b tmp; }結(jié)果交換成功原理swap拿到了x和y的鑰匙地址。它直接打開了main函數(shù)的柜子進(jìn)行了交換。內(nèi)存布局堆與棧Heap vs Stack計(jì)算機(jī)內(nèi)存被劃分為不同的區(qū)域其中兩個(gè)最重要的是1. 棧Stack用途存儲(chǔ)函數(shù)的局部變量、參數(shù)。特點(diǎn)自動(dòng)管理函數(shù)結(jié)束自動(dòng)釋放??臻g較小。不僅向下增長(zhǎng)高地址 - 低地址。問(wèn)題如果遞歸太深如無(wú)限遞歸會(huì)耗盡??臻g導(dǎo)致棧溢出Stack Overflow。2. 堆Heap用途存儲(chǔ)動(dòng)態(tài)分配的內(nèi)存malloc。特點(diǎn)手動(dòng)管理需要malloc和free??臻g很大。向上增長(zhǎng)低地址 - 高地址。問(wèn)題如果只借不還會(huì)耗盡堆空間導(dǎo)致堆溢出Heap Overflow或內(nèi)存泄漏。scanf 的使用與風(fēng)險(xiǎn)我們用過(guò)get_int那是CS50庫(kù)封裝好的。C語(yǔ)言原生的輸入函數(shù)是scanf。獲取整數(shù)int x; printf(x: ); // 必須給地址 x因?yàn)?scanf 需要修改 x 的值 scanf(%i, x);獲取字符串危險(xiǎn)char s[4]; // 只分配了4個(gè)字節(jié) printf(s: ); // s 本身就是地址不需要 scanf(%s, s);風(fēng)險(xiǎn)如果用戶輸入 hello5個(gè)字符 6字節(jié)。數(shù)組s只有4個(gè)字節(jié)。scanf會(huì)繼續(xù)往后寫覆蓋掉不屬于s的內(nèi)存這可能導(dǎo)致程序崩潰段錯(cuò)誤或安全漏洞緩沖區(qū)溢出攻擊。更安全的做法使用malloc分配足夠的空間或者限制讀取長(zhǎng)度。文件操作File I/OC語(yǔ)言可以讀寫文件這是持久化存儲(chǔ)數(shù)據(jù)的關(guān)鍵。寫入文件Phonebook示例#include cs50.h #include stdio.h #include string.h int main(void) { // 1. 打開文件 // a 表示 append追加模式 // 如果文件不存在會(huì)自動(dòng)創(chuàng)建 FILE *file fopen(phonebook.csv, a); if (file NULL) return 1; // 打開失敗檢查 char *name get_string(Name: ); char *number get_string(Number: ); // 2. 寫入文件 // fprintf 是 file printf向文件打印 fprintf(file, %s,%s , name, number); // 3. 關(guān)閉文件 fclose(file); }讀取文件復(fù)制圖片示例我們可以寫一個(gè)程序cp.c來(lái)復(fù)制文件即便是二進(jìn)制圖片。// cp.c - 復(fù)制文件 #include stdio.h #include stdint.h // 定義一個(gè)字節(jié)類型 typedef uint8_t BYTE; int main(int argc, char *argv[]) { // 檢查參數(shù) if (argc ! 3) { printf(Usage: ./cp SOURCE DESTINATION ); return 1; } // 打開源文件二進(jìn)制讀模式 rb FILE *src fopen(argv[1], rb); if (src NULL) return 1; // 打開目標(biāo)文件二進(jìn)制寫模式 wb FILE *dst fopen(argv[2], wb); if (dst NULL) return 1; BYTE buffer; // 緩沖區(qū)每次讀1個(gè)字節(jié) // 循環(huán)讀取直到文件結(jié)束 // fread 返回成功讀取的塊數(shù)為0表示讀完了 while (fread(buffer, sizeof(BYTE), 1, src) ! 0) { // 寫入目標(biāo)文件 fwrite(buffer, sizeof(BYTE), 1, dst); } // 關(guān)閉所有文件 fclose(dst); fclose(src); }說(shuō)明fread(buffer, size, qty, file)從文件讀數(shù)據(jù)到內(nèi)存。fwrite(buffer, size, qty, file)從內(nèi)存寫數(shù)據(jù)到文件。這種方式可以復(fù)制任何類型的文件文本、圖片、視頻因?yàn)樗僮鞯氖亲畹讓拥淖止?jié)。總結(jié)本周我們揭開了內(nèi)存的神秘面紗。我們學(xué)習(xí)了十六進(jìn)制更簡(jiǎn)潔地表示二進(jìn)制數(shù)據(jù)。地址與指針取地址*解引用。指針就是存儲(chǔ)地址的變量。字符串的本質(zhì)char *即指向首字符的指針。指針?biāo)阈g(shù)*(s1)等同于s[1]。動(dòng)態(tài)內(nèi)存malloc申請(qǐng)free釋放。避免內(nèi)存泄漏和段錯(cuò)誤。內(nèi)存交換必須使用指針引用傳遞。文件操作fopen,fclose,fread,fwrite。下周我們將利用這些知識(shí)學(xué)習(xí)數(shù)據(jù)結(jié)構(gòu)Data Structures看看如何在內(nèi)存中構(gòu)建更復(fù)雜、更高效的數(shù)據(jù)組織形式參考資料CS50 Week 4 官方筆記Pointer Fun with Binky (視頻) - 強(qiáng)烈推薦形象解釋指針。
版權(quán)聲明: 本文來(lái)自互聯(lián)網(wǎng)用戶投稿,該文觀點(diǎn)僅代表作者本人,不代表本站立場(chǎng)。本站僅提供信息存儲(chǔ)空間服務(wù),不擁有所有權(quán),不承擔(dān)相關(guān)法律責(zé)任。如若內(nèi)容造成侵權(quán)/違法違規(guī)/事實(shí)不符,請(qǐng)聯(lián)系我們進(jìn)行投訴反饋,一經(jīng)查實(shí),立即刪除!