內容提要
- 內存操作
- 內存操作的函數
內存操作
我們對于內存操作需要依賴于string.h
頭文件中相關的庫函數。
內存的庫函數
內存填充
- 頭文件:
#include <string.h>
- 函數原型
void* memset(void* s, int c, size_t)
- 函數功能:將內存塊
s
的前n
個字節填充為c
,一般用于初始化或者清零操作 - 參數說明:
s
:目標內存首地址c
:填充值(以unsigned char
形式處理0~255)n
:填充字節數
- 返回值:
- 成功:返回
s
的指針 - 失敗:返回NULL
- 成功:返回
- 注意事項:
- 常用于動態化初始化,c通常設置為0(清零)
- 按字節填充,非整型初始化需要謹慎(如填充int數組時,0是安全的)
- 案例:
#include <stido.h>
#include <stdilb.h>
#include <string.h>int main()
{// 在堆內存中申請4個int的連續空間int *p = (int*)malloc(4 * sizeof(int));// 非空校驗if (p == NULL){perror("內存申請失敗!");return -1;}// 初始化堆內存,填充0memset(p, 0, 4 * sizeof(int));// 測試輸出printf("%d\n", p[1]); // p[1] 的底層 *(p+1) 我們可以將p[1]看作是*(p+1)語法糖// 內存使用完畢,釋放free(p);// 對指針賦值NULLp = NULL;return 0;
}
內存拷貝
-
頭文件:
#include <string.h>
-
函數原型:
- 源域目標內存無重疊時使用
void* memcpy(void* dest, const void* src, size_t n);
- 安全處理內存重疊
void* memmove(void* dest, const void* src, size_t n);
-
函數功能:將
src
的前n
個字節拷貝倒dest
-
參數說明:
dest
: 目標內存首地址src
:源內存首地址size_t n
:拷貝的字節數
-
返回值
- 成功:返回
dest
的首地址 - 失敗:返回NULL
- 成功:返回
-
注意內存:
memmove
能正確處理內存重疊,推薦優先使用- 確保目標內存足夠大,避免溢出。
-
示例:
#include <stdio.h>
#include <string.h>int main()
{// 準備兩個數組,用來存護源和目標int src[4] = {11,22,33,44};int dest[6] = {111,222,333,444,555,666};// 進行拷貝memcpy(dest+1, src+1, 2 * sizeof(int));memmove(dest+1, src+1, 2 * sizeof(int)); // 從src拷貝22,33倒dest的222的位置printf("源數組:");register int i;for(i = 0; i < 4; i++) printf("%-6d", src[i]);printf("\n目標數組:");for(i = 0;i < 6; i++) printf("%-6d", dest[i]);return 0;
}
思考:什么是內存重疊?
內存重疊指在內存操作(如拷貝、移動數據)時,源區域和目標區域的內存地址范圍存在部分或完全重疊,導致操作結果出現不確定性。
典型例子:
memcpy
與memmove
memcpy
的隱患
假設拷貝
10字節
從地址p
到p+2
:char str[] = "abcdefgh"; memcpy(str + 2, str, 5); // 源和目標重疊,行為未定義!
memcpy
不檢查重疊,可能因逐字節拷貝導致數據被意外覆蓋(如先覆蓋a
到c
,后續操作又讀取被修改的值)。
memmove
的解決方案
同樣的操作,使用
memmove
會檢測重疊方向:
- 若目標地址在源之前(正向拷貝),或地址不重疊,直接拷貝。
- 若目標地址在源之后(反向拷貝),則從尾部開始倒序拷貝,避免覆蓋未讀取的數據。
memmove(str + 2, str, 5); // 安全處理重疊
內存比較
- 頭文件:
#include <string.h>
- 函數原型:
int memcmp(const void* s1, const void* s2, size_t n);
- 函數功能:比較
s1
和s2
的前n
個字節 - 返回值:
0
:內存內容相同>0
:s1
中第一個不同字節大于s2
<0
:s1
中第一個不同字節小于s2
- 注意事項:比較按字節進行,非字符串需確保長度一致(總字節數一致)
- 示例:
#include <stido.h>
#include <stdilb.h>
#include <string.h>int main()
{// 準備比較的數據int* arr1 = (int*)mallco(3 * sizeof(int)); // 3個元素int* arr2 = (int*)callco(4 * sizeof(in1t)); // 4個元素// 清零memset(arr1, 0, 3 * sizeof(int));// 賦值arr[0] = 60; arr[1] = 66;arr[0] = 70; arr2[1] = 5;// 比較int cmp_result = memcmp(arr2, arr1, 2 * sizeof(int)); // 雙方參與比較的字節數完全一致printf("比較結果:%d-(%s)\n", cmp_result, cmp_result > 0 ? "大于" : cmp_result < 0 ? "小于" : "等于");// 釋放內存free(arr1);free(arr2);arr1 = arr2 = NULL;return 0;
}
內存查找
-
頭文件:
#include <string.h>
-
函數原型:
- 正向查找, C語言標準庫函數
void* memchr(const void* s, int c, size_t n);
- 逆向查找,這個不是C語言標準庫函數,屬于GNU擴展
void* memrchr(const void* s, int c, size_t n);
-
函數功能:在
s
的前n
個字節中查找字符c
-
返回值:
- 成功:返回找到內容對應的地址
- 失敗:返回NULL
-
注意事項:
memrchr
是GNU擴展函數,需手動聲明(只要不是C語言標準提供,編譯的時候都需要手動聲明或鏈接)- 查找單位為字節值,非整型數據需要注意內存布局
-
示例:
#include <stido.h>
#include <string.h>// memrchr是GUN擴展函數,需要外部聲明
extern void* memrchr(const void*, int, size_t);int main()
{// 準備一個測試數組char str[] = {'A','B','C','B'};// 查找字符'B'char * first = (char*) memchr(str, 'B', sizeof(str));char * last = (char*) memrchr(str, 'B', sizeof(str)); // GUN擴展函數printf("first = %p, last=%p\n", first, last);printf("第1個B的位置, %ld\n", first -str); // 1printf("最后1個B的位置, %ld\n", last -str); // 3
}
``