=========================================================================
相關(guān)代碼gitee自取:
C語言學(xué)習(xí)日記: 加油努力 (gitee.com)
?=========================================================================
接上期:
學(xué)C的第二十八天【字符串函數(shù)和內(nèi)存函數(shù)的介紹(一)】_高高的胖子的博客-CSDN博客
?=========================================================================
? ? ? ? ? ? ? ? ? ? ? ??
1 . 函數(shù)介紹(續(xù))
(11). memcpy()函數(shù):
從存儲區(qū)?str2?拷貝n?個字節(jié)的數(shù)據(jù)到存儲區(qū)?str1
? ? ? ? ? ? ? ?
函數(shù)返回值類型和相關(guān)參數(shù):
? ? ? ? ? ? ?
void * memcpy ( void * destination, const void * source, size_t num );
? ? ? ? ? ? ? ?
(參數(shù)接收 任意類型的目標(biāo)空間地址 和 任意類型的常量源數(shù)據(jù)地址 和 拷貝的字節(jié)數(shù),
返回 任意類型的拷貝完成后的目標(biāo)空間地址)
? ? ? ? ? ? ? ? ? ??
注意事項:
(1).
函數(shù)memcpy從source的位置開始向后復(fù)制num個字節(jié)的數(shù)據(jù)到destination的內(nèi)存位置。
需要頭文件<string.h>。
? ? ? ? ? ? ? ? ??
(2).
這個函數(shù)在遇到 '\0' 的時候并不會停下來。
? ? ? ? ? ? ? ??
(3).
如果source和destination有任何的重疊,復(fù)制的結(jié)果都是未定義的。
? ? ? ? ? ? ? ?
(4).
學(xué)會memcpy函數(shù)的模擬實現(xiàn)(下面第2個模塊有)
? ? ? ? ? ? ? ? ? ? ?
? ? ? ? ? ? ? ? ? ??
(12). memmove()函數(shù):
從存儲區(qū)?str2?移動 n?個字節(jié)的數(shù)據(jù)到存儲區(qū)?str1
? ? ? ? ? ? ? ??
函數(shù)返回值類型和相關(guān)參數(shù):
? ? ? ? ? ? ?
void * memmove?( void * destination, const void * source, size_t num );
? ? ? ? ? ? ? ?
(參數(shù)接收 任意類型的目標(biāo)空間地址 和 任意類型的常量源數(shù)據(jù)地址 和 移動的字節(jié)數(shù),
返回 任意類型的移動完成后的目標(biāo)空間地址)
? ? ? ? ? ? ? ? ? ??
注意事項:
(1).
和memcpy的差別就是memmove函數(shù)處理的源內(nèi)存塊和目標(biāo)內(nèi)存塊是可以重疊的。
? ? ? ? ? ? ? ? ??
(2).
如果源空間和目標(biāo)空間出現(xiàn)重疊,就得使用memmove函數(shù)處理。
? ? ? ? ? ? ? ??
(3).
學(xué)會memmove函數(shù)的模擬實現(xiàn)(下面第2個模塊有)
? ? ? ? ? ? ? ? ? ? ?
? ? ? ? ? ? ? ? ? ??
(13). memcmp()函數(shù):
比較從ptr1和ptr2指針開始的num個字節(jié)
? ? ? ? ? ??
函數(shù)返回值類型和相關(guān)參數(shù):
? ? ? ? ? ? ?
int memcmp ( const void * ptr1, const void * ptr2, size_t num );
? ? ? ? ? ? ? ? ? ??
(參數(shù)接收 兩個任意類型的常量地址?和 比較的字節(jié)數(shù),
返回 一個整數(shù))
? ? ? ? ? ? ? ? ? ??
注意事項:
(1).?標(biāo)準(zhǔn)規(guī)定:
? ? ? ? ? ? ? ? ? ?
第一個元素 大于 第二個元素,則返回 大于0 的數(shù)字
? ? ? ? ? ? ?
第一個元素 等于 第二個元素,則 返回0
? ? ? ? ? ? ? ? ? ? ? ? ?
第一個元素 小于 第二個元素,則返回 小于0 的數(shù)字
? ? ? ? ?
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
? ? ? ? ? ? ?
2 . 庫函數(shù)的模擬實現(xiàn)(續(xù))
(6). 模擬實現(xiàn)memcpy()函數(shù):
模擬實現(xiàn)的自定義函數(shù):
? ? ? ? ? ? ? ? ??
主函數(shù):
? ? ? ? ? ? ? ? ? ? ? ?
對應(yīng)代碼:
//模擬memcpy()函數(shù): #include <stdio.h> #include <assert.h> void* my_memcpy(void* dest, const void* src, size_t num) //返回值為 拷貝結(jié)束后的目標(biāo)空間起始地址 //size_t num:參數(shù)接收的是 要拷貝的字節(jié)數(shù),因為不同類型的數(shù)據(jù)字節(jié)數(shù)是不同的 { //保存目標(biāo)空間的原始地址,方便拷貝完后返回原地址: void* ret = dest; //使用斷言,確保兩指針不是空指針: assert(dest && src); while (num--) //將兩個void*指針,轉(zhuǎn)化為char*指針,一個字節(jié)一個字節(jié)拷貝 //所以有幾個字節(jié)就拷貝幾次 { //轉(zhuǎn)化為char*指針,一個字節(jié)一個字節(jié)拷貝: //強制類型轉(zhuǎn)化只是臨時的: *(char*)dest = *(char*)src; //移動指針拷貝下一位: //因為void*指針不能++和*, //所以要轉(zhuǎn)化為char*后+1再賦給dest: dest = (char*)dest + 1; src = (char*)src + 1; } //返回原地址: return ret; } int main() { //源數(shù)據(jù): int arr1[] = { 1,2,3,4,5,6,7,8,9,10 }; //目標(biāo)空間: int arr2[20] = { 0 }; //將arr1的內(nèi)容拷貝到arr2中,因為是int類型不能使用strcpy函數(shù): //使用模擬的自定義函數(shù): my_memcpy(arr2, arr1, 20); //結(jié)果: int i = 0; for (i = 0; i < 20; i++) { printf("%d ", arr2[i]); } return 0; }
? ? ? ? ? ? ? ? ? ? ?
? ? ? ? ? ? ? ? ? ??
(7). 模擬實現(xiàn)memmove()函數(shù):
模擬實現(xiàn)的自定義函數(shù):
? ? ? ? ? ? ? ? ??
主函數(shù):
? ? ? ? ? ? ? ? ??
對應(yīng)代碼:
//模擬實現(xiàn)memmove函數(shù): #include <stdio.h> #include <assert.h> void* my_memmove(void* dest, const void* src, size_t num) // 目標(biāo)空間 原數(shù)據(jù)空間 (首元素地址) { //保存起始位置: void* ret = dest; //斷言: assert(dest && src); //如果源數(shù)據(jù)空間在目標(biāo)空間有重疊,則有2種情況: //1. 目標(biāo)空間首地址(dest) 在 源數(shù)據(jù)空間首地址左邊(src) , // 那就需要 從前往后 進行移動,才不會有源數(shù)據(jù)被覆蓋的情況 //2. 目標(biāo)空間首地址(dest) 在 源數(shù)據(jù)空間首地址右邊(src) , // 那就需要 從后往前 進行移動,才不會有源數(shù)據(jù)被覆蓋的情況 //如果兩個空間沒有重疊的情況,則 從前往后 還是 從后往前 移動都可以 //使用分兩種情況即可: //void* 不能解引用和+1-1操作,但可以比(地址)大小 if (dest < src) //第一種情況 { //從前往后 移動: while (num--) { *(char*)dest = *(char*)src; dest = (char*)dest + 1; src = (char*)src + 1; } } else //第二種情況 { //從后往前 移動: while (num--) { *((char*)dest + num) = *((char*)src + num); } } return ret; } int main() { //源數(shù)據(jù): int arr1[] = { 1,2,3,4,5,6,7,8,9,10 }; my_memmove(arr1, arr1+2, 20); //結(jié)果: int i = 0; for (i = 0; i < 10; i++) { printf("%d ", arr1[i]); } return 0; }
? ? ? ? ? ? ? ? ? ?
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
? ? ? ? ? ? ? ? ? ? ?
3 . 練習(xí)
(1). 楊氏矩陣:
? ? ? ? ??
題目:
有一個數(shù)字矩陣(二維數(shù)組),
矩陣的每行從左到右是遞增的,
矩陣從上到下是遞增的,
請編寫程序在這樣的矩陣中查找某個數(shù)字是否存在,要求:時間復(fù)雜度小于O(N)。
? ? ? ? ? ? ? ? ? ? ?
時間復(fù)雜度為O(N)的版本:
? ? ? ??
對應(yīng)代碼:
//正常寫法,時間復(fù)雜度為O(N): #include <stdio.h> int main() { //給出符合楊氏矩陣的二維數(shù)組: int arr[3][3] = { 1,2,3,4,5,6,7,8,9 }; //輸入要找的數(shù): int k = 0; scanf("%d", &k); //在二維數(shù)組中一個一個遍歷:時間復(fù)雜度為O(N) int i = 0; for (i = 0; i < 3; i++)//遍歷行 { int j = 0; for (j = 0; j < 3; j++)//遍歷列 { if (arr[i][j] == k)//如果找到了 { //進行打印: printf("找到了,它的下標(biāo)為:%d %d", i, j); return 0; //直接使用return結(jié)束程序, //break只能跳出一層循環(huán) } } } //未找到則打印未找到: printf("未找到"); return 0; }
? ? ? ? ? ??
時間復(fù)雜度小于O(N)的版本:
? ? ? ? ? ? ? ? ? ??
對應(yīng)代碼:
#include <stdio.h> void young_tableau_search(int arr[3][3], int k, int* px, int* py) { //開始查找,思路: //因為是楊氏矩陣,所以一行中最右邊的數(shù)是最大的 //這個最大值如果比要找的值都小的話,那就可以排除這一行 //列也是同理 // 坐標(biāo)(0,2),第一行的最大值 int x = 0; //二維數(shù)組的行 int y = *py-1; //二維數(shù)組的列 while (x <= *px-1 && y >= 0) //行最大調(diào)整到第二行,列最多調(diào)整到第0行 { if (arr[x][y] < k) //如果第一行的最大值都小于k, { x++; //排除這一行,移到下一行 } else if (arr[x][y] > k) //如果第一行的最大值大于k, { y--; //說明k可能就在這一行,移動列進行查找 } else { //找到了就把k的行和列賦給指針px和指針py: *px = x; *py = y; return; } } //自定義未找到的情況: *px = -1; *py = -1; } int main() { //給出符合楊氏矩陣的二維數(shù)組: int arr[3][3] = { 1,2,3,4,5,6,7,8,9 }; // 1 2 3 // 4 5 6 // 7 8 9 //輸入要找的數(shù): int k = 0; scanf("%d", &k); int x = 3; //k的行 int y = 3; //k的列 //自定義一個函數(shù)進行查找: young_tableau_search(arr, k, &x, &y); //參數(shù): 二維數(shù)組名,要找的值,行數(shù),列數(shù) //通過函數(shù)的使用情況打印相應(yīng)情況: if (x==-1 && y==-1) //未找到: { printf("未找到"); } else //找到了: { printf("找到了,它的下標(biāo)為:第%d行 第%d列", x, y); } return 0; }
? ? ? ? ? ? ? ? ? ? ?
? ? ? ? ? ? ? ? ? ??
(2). 字符串左旋:
? ? ? ? ??
題目:
實現(xiàn)一個函數(shù),可以左旋字符串中的k個字符。
? ? ? ? ?
例如:
ABCD左旋一個字符得到BCDA
ABCD左旋兩個字符得到CDAB? ? ? ? ? ? ?
方法1:左旋一個字符就移動一次剩余的字符
? ? ? ? ? ? ? ? ?
對應(yīng)代碼:
//方法1:左旋一個字符就移動一次剩余的字符 //實現(xiàn)一個函數(shù),可以左旋字符串中的k個字符。 //例如: //ABCD左旋一個字符得到BCDA //ABCD左旋兩個字符得到CDAB #include <stdio.h> #include <string.h> #include <assert.h> void left_move(char* str, int k) { //斷言:str不為空指針 assert(str); //左旋k次: int j = 0; for (j = 0; j < k; j++) { //存放被左旋字符的地址,從第一個字符開始 char tmp = *str; //求字符串長度: int len = strlen(str); //左旋后一個字符后,后面len-1個字符要往前挪一位 int i = 0; for (i = 0; i < len - 1; i++) { //把后一個字符賦給前一個 *(str + i) = *(str + i + 1); //這里就覆蓋掉了前面一個字符,末尾空出一個字符 } //將左旋的字符移動到尾部 *(str + len - 1) = tmp; } } int main() { char arr[] = "ABCD"; //輸入左旋次數(shù): int k = 0; scanf("%d", &k); //使用自定義函數(shù)進行左旋: left_move(arr, k); //參數(shù): 字符串首地址,左旋次數(shù) //打印左旋后結(jié)果: printf("%s\n", arr); return 0; }
? ? ? ? ? ? ? ? ? ??
方法2:
把字符串分為兩部分,左旋字符為一部分,剩余字符為一部分,分別進行逆序,再整體逆序
? ? ? ? ? ? ? ? ? ?文章來源地址http://www.zghlxwxcb.cn/news/detail-598436.html
對應(yīng)代碼:
//方法2: #include <stdio.h> #include <assert.h> #include <string.h> //定義一個逆序函數(shù): void reverse(char* left, char* right) { //斷言:兩指針不為空 assert(left && right); //進行逆序: while (left < right) //兩指針中間還有數(shù)就繼續(xù) { char tmp = *left; *left = *right; *right = tmp; left++; right--; } } void left_move(char* str, int k) { int len = strlen(str); k %= len;//防止重復(fù)操作 //求左旋字符進行逆序: reverse(str, str + k - 1); //對剩余字符進行逆序: reverse(str + k, str + len - 1); //整體逆序: reverse(str, str + len - 1); } int main() { char arr[] = "ABCD"; //輸入左旋次數(shù): int k = 0; scanf("%d", &k); //使用自定義函數(shù)進行左旋: left_move(arr, k); //參數(shù): 字符串首地址,左旋次數(shù) //打印左旋后結(jié)果: printf("%s\n", arr); return 0; }
? ? ? ? ? ? ??
(3). 字符串旋轉(zhuǎn)結(jié)果:
? ? ? ? ??
題目:
寫一個函數(shù),判斷一個字符串是否為另外一個字符串旋轉(zhuǎn)之后的字符串。
? ? ? ? ? ? ??
例如:
給定s1 =AABCD和s2 = BCDAA,返回1
給定s1=abcd和s2=ACBD,返回0.
? ? ? ? ? ??
AABCD左旋一個字符得到ABCDA
AABCD左旋兩個字符得到BCDAA
AABCD右旋一個字符得到DAABC
? ? ? ? ? ? ?
方法1:
str1每旋轉(zhuǎn)一次就和str2進行對比,不同則繼續(xù)進行下次旋轉(zhuǎn)
? ? ? ? ? ? ? ? ? ?
對應(yīng)代碼:
#include <stdio.h> #include <string.h> int is_left_move(char* str1, char* str2) { //求字符串長度: int len = strlen(str1); int j = 0; for (j = 0; j < len; j++) //字符串長度為幾,最多就旋轉(zhuǎn)幾次 { //存放被左旋字符的地址,從第一個字符開始 char tmp = *str1; //左旋后一個字符后,后面len-1個字符要往前挪一位 int i = 0; for (i = 0; i < len - 1; i++) { //把后一個字符賦給前一個 *(str1 + i) = *(str1 + i + 1); //這里就覆蓋掉了前面一個字符,末尾空出一個字符 } //將左旋的字符移動到尾部 *(str1 + len - 1) = tmp; //到這里就旋轉(zhuǎn)了1次, //每旋轉(zhuǎn)1次就使用strcmp判斷是否和str2相同: if (strcmp(str1, str2) == 0) { return 1;//找到返回1 } } //未找到就返回0 return 0; } int main() { char arr1[] = "ABCDEF"; char arr2[] = "CDEFAB"; //使用自定義函數(shù): int ret = is_left_move(arr1, arr2); //根據(jù)自定義函數(shù)返回結(jié)果進行打?。? if (ret == 1) { printf("Yes\n"); } else { printf("No\n"); } return 0; }
? ? ? ? ? ? ??
方法2:
把str1變成 “str1+str1”,如果?“str1+str1” 中有str2,那就可以通過str1旋轉(zhuǎn)得到str2
文章來源:http://www.zghlxwxcb.cn/news/detail-598436.html
? ? ? ? ? ? ? ? ? ?
對應(yīng)代碼:
#include <stdio.h> #include <string.h> int is_left_move(char* str1, char* str2) { int len1 = strlen(str1); int len2 = strlen(str2); //判斷兩字符串長度是否相同,不同的話肯定不能通過旋轉(zhuǎn)得到: if (len1 != len2) { return 0; } //通過strncat在str1上再追加str1: strncat(str1, str1, len1); //判斷追加后的str1中有沒有str2,有則可以通過旋轉(zhuǎn)得到: if (strstr(str1, str2) == NULL) { return 0; } else { return 1; } } int main() { char arr1[20] = "ABCDEF"; char arr2[] = "CDEFAB"; //使用自定義函數(shù): int ret = is_left_move(arr1, arr2); //根據(jù)自定義函數(shù)返回結(jié)果進行打印: if (ret == 1) { printf("Yes\n"); } else { printf("No\n"); } return 0; }
到了這里,關(guān)于學(xué)C的第二十九天【字符串函數(shù)和內(nèi)存函數(shù)的介紹(二)】的文章就介紹完了。如果您還想了解更多內(nèi)容,請在右上角搜索TOY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!