?? sizeof
?? strlen
?? strcpy
?? strncpy
?? strcmp
?? strncmp
?? strcat
?? strncat
?? strstr
?? strtok
?? streror
?? memcpy
?? memmove
?? memcmp
??sizeof準確的來講不是一個庫函數(shù),而是一個單目運算符。它的參數(shù)可以是數(shù)組、指針、類型、對象、函數(shù)等,用來計算一塊內(nèi)存的大小。如果是字符串,則用sizeof的時候計算結(jié)果是包含結(jié)束符‘\0’的,因為結(jié)束符也是占用空間的。
??sizeof是在編譯的時候就計算好了緩沖區(qū)的長度,因此不能拿來計算和返回動態(tài)分配的內(nèi)存大小。
實例:
#include#includeint main()
{int s[10] = {0 };
char s1[] = "abcdef";
char s2[10] = "abcdef";
printf("%d\n", sizeof(s));//輸出40
//初始化數(shù)組指定數(shù)組大小10個元素,每個元素類型是int,所以輸出10*4=40
printf("%d\n", sizeof(s1));//輸出7
//初始化數(shù)組時沒有指定大小,實際看數(shù)組占多大內(nèi)存
//abcdef占6個字節(jié),字符串初始化數(shù)組會默認攜帶一個'\0',所以大小為6+1=7
printf("%d\n", sizeof(s2));//輸出10;
//初始化數(shù)組時指定數(shù)組大小為10,每個元素是int,所以輸出10*1=10
return 0;
}
strlen計算字符串長度。該函數(shù)返回字符串的長度,從第一個字符開始,到結(jié)束符截止,但是不包括結(jié)束符。
注意返回值是一個無符號整形數(shù)據(jù)
庫函數(shù)中實現(xiàn)的strlen函數(shù): size_t strlen ( const char * str );
typedef unsigned int size_t;
size_t 表示無符號的整型
實例
int main()
{char s[] = "abcdef";
int ret = strlen(s);
printf("%d", ret);//輸出6
return 0;
}
模擬實現(xiàn):
#include#include
//法1 遍歷
size_t my_strlen1(const char* str)
{assert(*str != NULL);
int count = 0;
while (*str != '\0')
{str++;
count++;
}
return count;
}
//法2 遞歸
size_t my_strlen2(const char* str)
{//assert(*str != NULL);
if (*str != '\0') {return my_strlen2(str + 1) + 1;
}
else {return 0;
}
}
//法3 指針-指針
size_t my_strlen3(const char* str)
{const char* start = str;
assert(*str != '\0');
while (*str != '\0')str++;
return str - start;
}
int main()
{char s[50] = "adsljkfakdsfj";
printf("%d\n", my_strlen1(s));//輸出13
printf("%d\n", my_strlen2(s));//輸出13
printf("%d\n", my_strlen3(s));//輸出13
return 0;
}
strcpy庫函數(shù)中實現(xiàn)的strcpy函數(shù): char * strcpy ( char * destination, const char * source );
?
opies the C string pointed by source into the array pointed by destination, including the terminating null character (and stopping at that point)
將源指向的C字符串復(fù)制到目標指向的數(shù)組中,包括終止空字符(并在該點停止)
?
為避免溢出,目標指向的數(shù)組的大小應(yīng)足夠長,以包含與源相同的 C 字符串(包括終止空字符),并且不應(yīng)在內(nèi)存中與源重疊
實例:
int main()
{char s[50] = "asdfh";
char s1[20] = "dfajslk";
char* ret = strcpy(s, s1);//會返回一個地址
printf("%s", ret);//輸出dfajslk
return 0;
}
模擬實現(xiàn):
#include#include
char* my_strcpy(char* dest, const char* src)
{assert(dest && src);
char* ret = dest;
while (*dest++ = *src++);
return ret;
}
//模擬實現(xiàn)strcpy
int main()
{char s[50] = "asdfh";
char s1[20] = "dfajslk";
char* ret = my_strcpy(s, s1);
printf("%s", ret);//輸出dfajslk
return 0;
}
strncpy??函數(shù)定義:char * strncpy ( char * destination, const char * source, size_t num );
??將源的第一個字符數(shù)復(fù)制到目標。如果在復(fù)制 num 個字符之前找到源 C 字符串的末尾(由 null 字符表示),則目標將填充零,直到總共寫入 num 個字符為止。
??如果源長度超過 num,則不會在目標末尾隱式附加空字符。因此,在這種情況下,不應(yīng)將目標視為以空結(jié)尾的 C 字符串(這樣讀取它會溢出)。
復(fù)制指針source 指向的內(nèi)存中的前num個字符到指針destination指向的內(nèi)存塊,包括結(jié)束符。
??如果num個數(shù)大于source的字符個數(shù),則依然復(fù)制num個字符,多的那部分填充’\0’ 。
??如果num個數(shù)少于source的字符的個數(shù),則字符串destination不是以結(jié)束符結(jié)尾,此??時如果訪問字符串destination可能會導(dǎo)致溢出,應(yīng)該手動填充結(jié)束符。
實例:
#define _CRT_SECURE_NO_WARNINGS 1
#include#includeint main()
{char s1[] = "asdhkjadsg";
char s2[50];
char* ret = strncpy(s2, s1,5);
*(ret + 5) = '\0';//手動添加結(jié)束標志
printf("%s\n", ret);//輸出asdhk
printf("%s\n", s2);//輸出asdhk
return 0;
}
strcmp??函數(shù)定義: int strcmp ( const char * str1, const char * str2 );
??比較兩個字符串,從字符串的首位開始比較起,如果他們相等,則依次往后,直到遇到不相同的字符,或直到結(jié)束符。如果字符串1和字符串2相等,則返回0,如果str1小于str2,則返回負數(shù),如果str1大于str2,則返回正數(shù)。
實例:
int main()
{char s1[] = "asdfjz";
char s2[] = "asdfjh";
int ret = strcmp(s1, s2);
printf("%d", ret);//輸出1
return 0;
}
模擬實現(xiàn):
#include#include
//模擬實現(xiàn)strcmp
int my_strcmp(const char* str1, const char* str2)
{assert(str1 && str2);
//判斷首字符是否相同,若是相同進入while循環(huán)繼續(xù)判斷下一個
while (*str1 == *str2)
{if (*str1 == '\0')//當(dāng)兩個字符串遍歷完仍然相同時
{ return 0;//返回0表示兩個字符串相同
}
str1++; str2++;
}
//判斷大小
if (*str1 >*str2)return 1;
else return -1;
}
int main()
{char s1[] = "asdfjz";
char s2[] = "asdfjh";
int ret = my_strcmp(s1, s2);
printf("%d", ret);//輸出1
return 0;
}
strncmp??函數(shù)聲明:int strncmp ( const char * str1, const char * str2, size_t num );
??將 C 字符串 str1 的字符數(shù)與 C 字符串 str2 的字符數(shù)進行比較。
??此函數(shù)開始比較每個字符串的第一個字符。如果它們彼此相等,則繼續(xù)使用以下對,直到字符不同,直到達到終止的空字符,或者直到兩個字符串中的 num 字符匹配,以先發(fā)生者為準
實例:
#define _CRT_SECURE_NO_WARNINGS 1
#include#includeint main()
{char s1[] = "abcdefgg";
char s2[] = "abcdefgh";
int ret = strncmp(s1, s2,8);
if (ret >0)
{printf("s1 >s2\n");
}else if(ret==0)
{printf("s1 = s2");
}
else {printf("s1< s2");
}
return 0;//輸出 s2 >s1
}
模擬實現(xiàn):
#include#include#include
int my_strncmp(const char* str1, const char* str2, int num)
{assert(str1 && str2);
while (*str1 == *str2)
{while (num>0)
{ if (*str1 == *str2)//如果兩個指針解引用指向的字符相同,就迭代往后走
{ str1++; str2++;
}
else {//如果碰到不同的,則返回兩個字符之間的差
return *str1 - *str2;
}
num -- ;
}
if (num == 0)
{ return 0;
}
}
return *str1 - *str2;
}
int main()
{char str1[] = "abcde";
char str2[] = "abcdf";
int ret = my_strncmp(str1, str2, 4);
int ret1 = my_strncmp(str1, str2, strlen(str2));
printf("%d\n", ret);
printf("%d\n", ret1);
return 0;
}
strcat??函數(shù)聲明:char * strcat ( char * destination, const char * source );
??連接字符串。將指針source 指向的字符串連接在指針destination指向的字符串后面,并且原來字符串的結(jié)束符會被source的首字符覆蓋掉,surce的結(jié)束符也會轉(zhuǎn)移過去,成為形成的新的字符串的結(jié)束符。
??連接成功則返回dset的首地址,失敗則返回空指針。
實例:
#define _CRT_SECURE_NO_WARNINGS 1
#include#includeint main()
{char s1[20] = "asd";
char* ret = strcat(s1, "hhl");//將字符串"hhl"追加到s1后面
if (ret != NULL)
{printf("%s\n", ret);//輸出 asdhhl
}
else {printf("沒有追加成功\n");
}
return 0;
}
模擬實現(xiàn):
#include#include
char* my_strcat(char* dest, const char* src)
{assert(dest && src);
char* ret = dest;
//1.找到目標空間的\0
while (*dest != '\0')dest++;
//2.追加
while (*dest++ = *src++) {;
}
return ret;
}
int main()
{char s[50] = "dsal";
char s1[] = "daskf";
char* ret = my_strcat(s, s1);
printf("%s",ret);//輸出dsaldaskf
return 0;
}
strncat??函數(shù)聲明:char * strncat ( char * destination, const char * source, size_t num );
?
??將指針source 指向的字符串的num個連接在指針destination指向的字符串后面,并且原來字符串的結(jié)束符會被source的首字符覆蓋掉,
實例:
#define _CRT_SECURE_NO_WARNINGS 1
#include#includeint main()
{char s1[20] = "adas";
char s2[] = "hh";
char* ret = strncat(s1, s2, sizeof(s2));
printf("%s", ret);//輸出adashh
return 0;
}
模擬實現(xiàn):
#include#include
#includechar* my_strncat(char* dest, const char* src, int size_t)
{assert(dest && src);
char* ret = dest;
while (*dest != '\0')dest++;
while (size_t-- >0)//size_t=3
{if (*src == '\0') { //如果src指向的字符串不夠size_t賦值長度,則補0
*dest = 0;
dest++;
}
else { //把src中的字符放入到dest中
*dest = *src;
dest++; src++;
}
*dest ='\0';//手動補字符串結(jié)束標志
}
return ret;//返回dest字符串起始地址
}
int main()
{char str1[20] = "abcd";
char str2[] = "efg";
char* ret = my_strncat(str1, str2, strlen(str2));
puts(ret);
return 0;
}
strstr??函數(shù)聲明:*char * strstr ( const charstr1, const char * str2);
?
??定位子字符串返回指向 str1 中第一次出現(xiàn)的 str2 的指針,如果 str2 不是 str1 的一部分,則返回空指針。
實例:
#define _CRT_SECURE_NO_WARNINGS 1
#include#includeint main()
{char s1[20] = "adasadsdf";
char s2[] = "asad";
char* ret = strstr(s1, s2); //返回s2在字符串s1中首次出現(xiàn)的位置
printf("%s", ret); //輸出asadsdf
return 0;
}
模擬實現(xiàn):
#include#include
//模擬實現(xiàn)strstr
char* my_strstr(const char* str1, const char* str2)
{const char* s1 = str1;
const char* s2 = str2;
const char* cp = s1;
while (*cp) //判斷當(dāng)前指針cp指向的位置的字符是不是結(jié)束標志,如果不是,繼續(xù)進入循環(huán)
{s1 = cp;
s2 = str2;
while (*s1 != '\0' && *s2 != '\0' && *s1 == *s2)
//字符串s1不結(jié)束,s2不結(jié)束,并且*s1跟*s2指向的字符相同,遍歷往后走
{ s1++; s2++;
}
if (*s2 == '\0') //如果字符串s2遍歷完依舊沒有跳出循環(huán),表示s2在字符串s1中出現(xiàn)
{ return cp;//返回當(dāng)前位置
}
cp++;//當(dāng)前指針向后遍歷
}
return NULL;
}
int main()
{char s[] = "adafassb";
char s1[] = "sb";
printf("%s", my_strstr(s, s1));
return 0;
}
strtok??函數(shù)聲明:char * strtok ( char * str, const char * sep );
??
??對此函數(shù)的一系列調(diào)用將 str 拆分為標記,這些標記是由分隔符中的任何字符分隔的連續(xù)字符序列。
在第一次調(diào)用時,該函數(shù)需要一個 C 字符串作為 str 的參數(shù),其第一個字符用作掃描令牌的起始位置。在后續(xù)調(diào)用中,該函數(shù)需要一個空指針,并使用最后一個令牌末尾之后的位置作為掃描的新起始位置。
??
??為了確定標記的開頭和結(jié)尾,該函數(shù)首先從起始位置掃描分隔符中未包含的第一個字符(該字符將成為標記的開頭)。然后從令牌的開頭開始掃描分隔符中包含的第一個字符,該字符將成為令牌的末尾。如果找到終止空字符,掃描也會停止。
??
??令牌的此結(jié)尾將自動替換為空字符,并且令牌的開頭由函數(shù)返回。
??一旦在對 strtok 的調(diào)用中找到 str 的終止空字符,則對此函數(shù)的所有后續(xù)調(diào)用(以空指針作為第一個參數(shù))都將返回空指針。
??找到最后一個令牌的點由要在下一次調(diào)用中使用的函數(shù)在內(nèi)部保留(不需要特定的庫實現(xiàn)來避免數(shù)據(jù)爭用)。
實例:
#define _CRT_SECURE_NO_WARNINGS 1
#include#includeint main()
{char arr[] = "Tzhenchuan@yeah.net";
char* p = "@.";
char* ret = NULL;
for (ret = strtok(arr, p);ret != NULL; ret = strtok(NULL, p))
{printf("%s\n", ret);
}
// 輸出
// Tzhenchuan
// yeah
// net
return 0;
}
streror??函數(shù)聲明:char * strerror ( int errnum );
?
??調(diào)用函數(shù)strerror時,如果程序有錯誤就會產(chǎn)生一個錯誤碼存放在errno中,使用函數(shù)sererror就可以打印出程序所報錯誤的類型
案例:
#define _CRT_SECURE_NO_WARNINGS 1
#include#include#include//fopen()函數(shù)如果打開文件成功,就會返回一個有效的指針
// 如果打開失敗,就會返回一個空(NULL)指針
int main()
{//打開文件 打開的是當(dāng)前目錄下面的文件 打開方式是r
FILE* pf = fopen("test.txt", "r");
if (pf == NULL)
{printf("%s\n",strerror(errno));
//輸出No such file or directory
//錯誤信息是沒有這個文件或者文件夾
return 1;
}
fclose(pf);
pf = NULL;
return 0;
}
memcpy??函數(shù)定義:void * memcpy ( void * destination, const void * source, size_t num );
?
??函數(shù)memcpy從source的位置開始向后復(fù)制num個字節(jié)的數(shù)據(jù)到destination的內(nèi)存位置。
??這個函數(shù)在遇到 ‘\0’ 的時候并不會停下來。
??如果source和destination有任何的重疊,復(fù)制的結(jié)果都是未定義的
實例:
int main()
{int arr1[] = {1,2,3,4,5,6,7,8,9,10 };
int arr2[20] = {0 };
memcpy(arr2, arr1, 20);
for (int i = 0; i< 10; i++)
{printf("%d ", arr2[i]);
}//輸出結(jié)果:1 2 3 4 5 0 0 0 0 0
return 0;
}
模擬實現(xiàn):
#include#include
void* my_memcpy(void* dest, const char* src,size_t num)
{//設(shè)計函數(shù)的時候為了使得傳入的數(shù)據(jù)兼容,采用void*指針接受可以兼容傳入的指針
//將void*指針統(tǒng)一強轉(zhuǎn)成(char*)指針進行操作,參數(shù)傳入的num實際上表示要改變多少個字節(jié)的值
void* ret = dest;//存放要返回的地址
assert(dest && src);
while (num-- )//循環(huán)num次
{*(char*)dest = *(char*)src;//將void*類型強轉(zhuǎn)成char*并對其所指向的內(nèi)存進行賦值
dest = (char*)dest + 1;//由于dest跟src指針強轉(zhuǎn)只是暫時的,不能進行自增操作
src = (char*)src + 1;//采用表達式的方式進行對dest和src指針的增操作
}
return ret;
}
int main()
{int arr1[] = {1,2,3,4,5,6,7,8,9 };
int arr2[10] = {0 };
my_memcpy(arr2, arr1 + 2, 20);
return 0;
}
memmove??函數(shù)聲明:void * memmove ( void * destination, const void * source, size_t num );
?
??和memcpy的差別就是memmove函數(shù)處理的源內(nèi)存塊和目標內(nèi)存塊是可以重疊的。
??如果源空間和目標空間出現(xiàn)重疊,就得使用memmove函數(shù)處理
??
??移動內(nèi)存塊將數(shù)字字節(jié)的值從源指向的位置復(fù)制到目標所指向的內(nèi)存塊。
實例:
#include#include
int main()
{int s[] = {1,2,3,4,5,6,7,8,9 };
memmove(s+2, s, 20);//數(shù)組內(nèi)容變?yōu)?1,2,1,2,3,4,5,8,9
//從s數(shù)組第三個元素開始改為數(shù)組s第一個元素開始的5個元素 內(nèi)存重疊
return 0;
}
模擬實現(xiàn):
#include#include
void* my_memmove(char* dest, const char* src, size_t num)
{assert(dest && src);
//為了使內(nèi)存重疊時也能進行操作,判斷dest和src指針的位置進行兩種不同的方式進行賦值操作
//memcpy原先設(shè)計的時候在內(nèi)存重疊的時候操作會出錯,memmove可以說是memcpy的改進版
if (dest< src)
{while (num--) { *(char*)dest = *(char*)src;//同上一個函數(shù)my_memcpy原理一樣
dest = (char*)dest + 1;
src = (char*)src + 1;
}
}
else {while (num--)
{ *((char*)dest + num) = *((char*)src + num);
}
}
}
int main()
{int s[] = {1,2,3,4,5,6,7,8,9 };
my_memmove(s+2, s, 20);
return 0;
}
memcmp??函數(shù)聲明:int memcmp ( const void * ptr1, const void * ptr2, size_t num );
??
??將 ptr1 指向的內(nèi)存塊的前 num 字節(jié)數(shù)與 ptr2 指向的第一個字節(jié)數(shù)進行比較,如果它們都匹配,則返回零,如果不匹配,則返回一個不同于零的值,表示哪個值更大。 請注意,與 strcmp 不同,該函數(shù)在找到空字符后不會停止比較
實例:
#include#includeint main()
{char buffer1[] = "DWgaOtP12df0";
char buffer2[] = "DWGAOTP12DF0";
int n;
n = memcmp(buffer1, buffer2, sizeof(buffer1));
//比較兩個字符串,返回一個值表示兩個字符串的大小關(guān)系
if (n >0)
{printf("'%s' is greater than '%s'.\n", buffer1, buffer2);
}
else if (n< 0)
{printf("'%s' is less than '%s'.\n", buffer1, buffer2);
}
else {printf("'%s' is the same as '%s'.\n", buffer1, buffer2);
}
//輸出'DWgaOtP12df0' is greater than 'DWGAOTP12DF0'
return 0;
}
你是否還在尋找穩(wěn)定的海外服務(wù)器提供商?創(chuàng)新互聯(lián)www.cdcxhl.cn海外機房具備T級流量清洗系統(tǒng)配攻擊溯源,準確流量調(diào)度確保服務(wù)器高可用性,企業(yè)級服務(wù)器適合批量采購,新人活動首月15元起,快前往官網(wǎng)查看詳情吧