国产xxxx99真实实拍_久久不雅视频_高清韩国a级特黄毛片_嗯老师别我我受不了了小说

資訊專欄INFORMATION COLUMN

【C語言進階】字符串&內存函數

pingan8787 / 3434人閱讀

摘要:字符串常量適用于那些對它不做修改的字符串函數。同時,語言提供了一系列庫函數來對操作字符串,這些庫函數都包含在頭文件中。目標空間必須足夠大,以確保能存放源字符串。拷貝個字符從源字符串到目標空間。

前言:

????????字符串是一種非常重要的數據類型,但是C語言不存在顯式的字符串類型,C語言中的字符串都以字符串常量的形式出現或存儲在字符數組中。字符串常量適用于那些對它不做修改的字符串函數。同時,C 語言提供了一系列庫函數來對操作字符串,這些庫函數都包含在頭文件 string.h 中。?

目錄

一、求字符串長度

strlen

strlen函數的模擬實現

二、長度不受限制的字符串函數

strcpy

strcpy函數的模擬實現

strcat

strcat函數的模擬實現

strcmp

strcmp函數的模擬實現

三、長度受限制的字符串函數

strncpy

strncpy函數的模擬實現

strncat

strncat函數的模擬實現

strncmp

strncmp函數的模擬實現

四、字符串查找

strstr

strstr函數的模擬實現

strtok

strtok函數的模擬實現

五、錯誤信息報告

strerror

六、字符操作

字符分類函數

?字符轉換

七、內存操作函數

memcpy

memcpy函數的模擬實現

memmove

memmove函數的模擬實現

memset

memcmp



一、求字符串長度

strlen

size_t strlen ( const char * str );
  • 字符串已經 "/0" 作為結束標志,strlen函數返回的是在字符串中 "/0" 前面出現的字符個數(不包含 "/0" )
  • 參數指向的字符串必須要以 "/0" 結束
  • 注意函數的返回值為size_t,是無符號的( 易錯 )
  • 學會strlen函數的模擬實現

源字符串必須以 "/0" 結束。 會將源字符串中的 "/0" 拷貝到目標空間。 目標空間必須足夠大,以確保能存放源字符串。 目標空間必須可變。 學會模擬實現。

例1:

#include #include int main(){    int len1 = strlen("abcdef");    printf("%d/n", len1); //6    char arr[] = {"a","b","c","d","e","f"};    //錯誤寫法    int len2 = strlen(arr);    printf("%d/n", len2); //隨機值    return 0;}

執行結果:?

例2:

int main(){    if(strlen("abc") - strlen("abcdef") > 0)        printf("hehe/n");    else        printf("haha/n");    system("pause");    return 0;}

執行結果:

?由于此時的strlen沒有進行定義,它的默認類型為無符號類型,那么兩個無符號數相加減最后得出的數是一個很大的數,所以最后的結果必然是大于0的

strlen函數的模擬實現

(1)計數器

#include #include int my_strlen(const char *str){    int count = 0;    assert(str != NULL);    while(*str != "/0")    {        count++;        str++;    }    return count;}int main(){    int len = my_strlen("abcdef");    printf("%d/n", len);    return 0;}

?(2)指針-指針

#include int my_strlen(const char *str){	  const char *p = str;	  while(*p != "/0")	  {	  	  p++;	  }	  return p-str;}int main(){	  int len = 0;	  char arr[10]="abcdef";	  len = my_strlen(arr);	  printf("%d/n", len);	  return 0;}

(3)遞歸

不創建臨時變量求字符串長度

#includeint my_strlen(const char *str){	  if(*str=="/0")		    return 0;	  else  	    return 1+my_strlen(str+1);}int main(){    int len = 0;	  char arr[10]="abcdef";	  len = my_strlen(arr);	  printf("%d/n", len);    return 0;}

二、長度不受限制的字符串函數

strcpy

char* strcpy(char * destination, const char * source);
  • 將按源指向的 C 字符串復制到按目的地指向的陣列中,包括終止空字符 (并停止在那個時候)?
  • 源字符串必須以 "/0" 結束
  • 會將源字符串中的 "/0" 拷貝到目標空間
  • 目標空間必須足夠大,以確保能存放源字符串
  • 目標空間必須可變。 學會模擬實現

例:

#include int main(){    char arr1[] = "abcdefghi";    char arr2[] = "bit";    //錯誤示范    //char *arr1 = "abcdefghi";    //p指向常量字符串,而常量字符串無法被修改    //char arr2[] = {"b","i","t"};    //由于此時沒有給"/0",由于找不到"/0"會導致向后越界訪問    strcpy(arr1, arr2);     printf("%s/n", arr1);    return 0;}

strcpy函數的模擬實現

#include #include char *my_strcpy(char *dest, const char *src){    assert(dest != NULL);    assert(src != NULL);    char *ret = dest;    //拷貝src指向的字符串到dest指向的空間,包含"/0"    while(*dest++ = *src++)    {        ;    }    //返回目的的空間的初始地址    return ret;//"/0"}int main(){    char arr1[] = "abcdefgh";    char arr2[] = "bit";    my_strcpy(arr1, arr2);     printf("%s/n", arr1);    return 0;}

strcat

char * strcat ( char * destination, const char * source );
  • 將源字符串的副本附加到目的地字符串。終止無效字符在目的地由源的第一個字符覆蓋,并在源的末尾包含空字符由目的地兩者的連結形成的新字符串
  • 源字符串必須以 "/0" 結束
  • 目標空間必須有足夠的大,能容納下源字符串的內容
  • 目標空間必須可修改
  • 字符串自己如何給自己追加

例:?

#include int main(){    char arr1[30] = "hello/0xxxxxxx";    char arr2[] = "wolrd";    strcat(arr1, arr2);    printf("%s/n", arr1);    //錯誤示范    char arr3[] = "hello";    char arr4[] = "world";    strcat(arr3, arr4);    printf("%s/n", arr3);    //由于arr3數組沒有定義空間大小    //此時就開辟了"hello/0"6個字節    //當arr4數組追加過去后就產生了越界訪問,產生報錯    return 0;}

調試結果:?

執行結果:

總結:此時我們可以看到,arr2數組內的的字符串從arr1數組中的"/0"開始進行追加

當arr2數組內的字符串追加過去后,后面的‘/0’也一并追加了過去

當目標空間不夠大時,就會造成訪問越界

strcat函數的模擬實現

#include #include char *my_strcat(char *dest, const char *src){    assert(dest != NULL);    assert(src);    char *ret = dest;     //1.找到目的字符串的"/0"    while(*dest != "/0")    {        dest++;    }    //2.追加    while(*dest++ = *src++)    {        ;    }    return ret;} int main(){    char arr1[30] = "hello";    char arr2[] = "wolrd";    my_strcat(arr1, arr2);    printf("%s/n", arr1);    return 0;}

strcmp

int strcmp (const char * str1, const char * str2 );

此函數開始比較每個字符串的第一個字符。 如果它們彼此相等,則繼續使用以下對,直到字符不同或到達終止空字符為止。?

標準規定:

  • 第一個字符串大于第二個字符串,則返回大于0的數字
  • 第一個字符串等于第二個字符串,則返回0
  • 第一個字符串小于第二個字符串,則返回小于0的數字
  • 那么如何判斷兩個字符串?
#include #include int main(){    char *p1 = "qbc";    char *p2 = "abc";    // int ret = strcmp(p1, p2);    // printf("%d/n", ret);    if(strcmp(p1, p2) > 0)    {        printf("p1 > p2/n");    }    else if(strcmp(p1, p2) == 0)    {        printf("p1 == p2/n");    }    else if(strcmp(p1, p2) < 0)    {        printf("p1 < p2/n");    }    return 0;}

strcmp函數的模擬實現

#include #include int my_strcmp(const char *str1, const char *str2){    assert (str1 && str2);    // 比較    while(*str1++ == *str2++)    {        if(*str1 == "/0")        {            return 0;//等于        }     }    if(*str1 > *str2)        return 1;//大于    else        return -1;//小于    //return (*str1 - *str2);    //通過相減判斷大于或小于}int main(){    char *p1 = "abcdef";    char *p2 = "abqwe";    int ret = my_strcmp(p1, p2);    printf("ret = %d/n", ret);    return 0;}

三、長度受限制的字符串函數

strncpy

char * strncpy ( char * destination, const char * source, size_t num );//單位是字節
  • ?將源的前 num 個字符復制到目標。 如果在復制 num 個字符之前找到源 C 字符串的結尾(由空字符表示),則用零填充目標,直到總共寫入了 num 個字符。
  • 拷貝num個字符從源字符串到目標空間。
  • 如果源字符串的長度小于num,則拷貝完源字符串之后,在目標的后邊追加0,直到num個。

?例1:

int main(){    char arr1[10] = "abcdefgh";    char arr2[] = "bit";    stcncpy(arr1, arr2, 6);    return 0;}

調試結果:?

?例2:

#include #include int main(){    char arr1[10] = "abcdefgh";    char arr2[] = "bit";    strncpy(arr1, arr2, 6);    return 0;}

調試結果:?

?由此可見,strncpy函數能拷貝任意長度的字符,當拷貝的字符長度不夠拷貝數時,用 "/0" 進行補充,直到拷貝數相等

strncpy函數的模擬實現

#include #include void my_strncpy(char *dest, const char *src, int n){    assert(src);    char* p1 = dest;    const char* p2 = src;    while (n--)    {        *p1++ = *p2++;    }}int main(){    char arr1[20] = "hello"    char arr2[] = "world";    my_strncpy(arr1, arr2, 3);    return 0;}

strncat

char * strncat ( char * destination, const char * source, size_t num );
  • 將源的前 num 個字符附加到目標,再加上一個終止空字符
  • 如果 source 中 C 字符串的長度小于 num,則只復制終止空字符之前的內容。

例1:

#include #include int main(){    char arr1[30] = { "hello/0xxxxxx" };    char arr2[] = "world";    strncat(arr1, arr2, 4);    return 0;}

調試結果:?

例2:

int main(){    char arr1[30] = { "hello/0xxxxxxxxx" };    char arr2[] = "world";    strncat(arr1, arr2, 8);    return 0;}

調試結果:

?由此可見,不管追加幾個數,都會在追加字符串后加上 "/0",而一旦追加數超過了追加字符串的長度,在追加完整字符串后面再加上"/0"后便結束了

strncat函數的模擬實現

#include#include#includevoid my_strncat(char* dest, const char* src, int len1, int len2, int n){	char* ret = dest + len1;	assert(src);	assert(n <= len2);	while ((n--) && (*ret++ = *src++))    {		;    }}int main(){	char arr1[20] = "abcd";	char arr2[] = "efghi";	int len1 = strlen(arr1);	int len2 = strlen(arr2);	int n = 0;	scanf("%d", &n);	my_strncat(arr1, arr2, len1, len2, n);	return 0;}

strncmp

int strncmp ( const char * str1, const char * str2, size_t num );
  • 比較到出現另個字符不一樣或者一個字符串結束或者num個字符全部比較完。

例:

#include #include int main(){    const char* p1 = "abcdef";    const char* p2 = "abcqwer";    int ret = strncmp(p1, p2, 4);    printf("%d/n", ret);}

執行結果:

strncmp函數的模擬實現

#include#include#includeint my_strncmp(const char *dest, const char *src, int n){	int ret = 0;	assert(dest);	assert(src);	assert(n);	while( (n--) && !(ret = (unsigned char)*dest-(unsigned char)*src) && *dest )	{		dest++;		src++;	}	return ret;}int main(){	char arr1[] = "abcdef";	char arr2[] = "abcedef";	int n = 0;	int ret = 0;	int i = 0;	scanf("%d",&n);	ret = my_strncmp(arr1, arr2, n);	if(ret == 0)	{		for(i=0; i");		for(i=0; i

四、字符串查找

strstr

char * strstr ( const char *, const char * );
  • 返回指向 str1 中第一次出現 str2 的指針,如果 str2 不是 str1 的一部分,則返回空指針。

例:

int main(){    char *p1 = "abcdefabcdef";    char *p2 = "def";    char * ret = strstr(p1, p2);    if(ret == NULL)    {        printf("子串不存在");    }    else    {        printf("%s/n", ret);    }    system("Pause");    return 0;}

執行結果:

?由此可得出,當有主字符串中存在兩個及以上子串時,優先按第一次出現相同的地址進行打印,并且會一直打印完剩下的字符串

strstr函數的模擬實現

#include #include //KMP 算法char *my_strstr(const char *p1, const char *p2){    assert(p1 != NULL);    assert(p2 != NULL);    char *s1 = NULL;    char *s2 = NULL;    char *cur = (char*)p1;//當前指針current    if(*p2 == "/0")    {        return (char*)p1;    }    while(*cur)    {        s1 = cur;        s2 = (char*)p2;        while(*s1 && *s2  && (*s1 == *s2))        {            s1++;            s2++;        }        if(*s2 == "/0")        {            return cur;//找到子串        }        cur++;    }    return NULL;//找不到子串}int main(){    char *p1 = "abcdef";    char *p2 = "def";    char * ret = my_strstr(p1, p2);    if(ret == NULL)    {        printf("子串不存在/n");    }    else    {        printf("%s/n", ret);    }    return 0;}

strtok

char * strtok (char *str, const char *sep);
  • sep參數是個字符串,定義了用作分隔符的字符集合
  • 第一個參數指定一個字符串,它包含了0個或者多個由sep字符串中一個或者多個分隔符分割的標記。
  • strtok函數找到str中的下一個標記,并將其用 /0 結尾,返回一個指向這個標記的指針。(注:strtok函數會改 變被操作的字符串,所以在使用strtok函數切分的字符串一般都是臨時拷貝的內容并且可修改。)
  • strtok函數的第一個參數不為 NULL ,函數將找到str中第一個標記,strtok函數將保存它在字符串中的位置。
  • strtok函數的第一個參數為 NULL ,函數將在同一個字符串中被保存的位置開始,查找下一個標記。
  • 如果字符串中不存在更多的標記,則返回 NULL 指針。

例:

#include #include int main(){    char arr[] = "qpzyahxf@163.com";    char *p = "@.";    char buf[1024] = {0};    //strtok會改變字符串內容,buf防止原字符串被切割(保護原始數據)    strcpy(buf, arr);    //切割buf中的字符串    char *ret = NULL;    for(ret = strtok(arr, p); ret != NULL; ret = strtok(NULL, p))    {        printf("%s/n", ret);    }    // char *ret = strtok(arr, p);    // printf("%s/n", ret);    // ret = strtok(NULL, p);    // printf("%s/n", ret);    // ret = strtok(NULL, p);    // printf("%s/n", ret);    return 0;}

執行結果:

strtok函數的模擬實現

#include char *my_strtok(char *str1 ,char *str2){    static char *p_last = NULL;    if(str1 == NULL && (str1 = p_last) == NULL)    {        return NULL;    }       char *s = str1;    char *t = NULL;    while(*s != "/0")    {        t = str2;        while(*t != "/0")        {            if(*s == *t)            {                p_last = s + 1;                if( s - str1 == NULL)                {                    str1 = p_last;                    break;                }                *s = "/0";                return str1;            }            t++;        }        s++;      }      return NULL;}int main() {     char arr[] = "qpzyahxf@163.com";    char *ret = NULL;    char *p = "@.";    for(ret =  my_strtok(arr, p); ret != NULL; ret = my_strtok(NULL, p))    {        printf("%s/n", ret);    }    return 0; } 

五、錯誤信息報告

strerror

char * strerror(int errum);

返回錯誤碼,所對應的錯誤信息。

???????例1:

#include #include int main(){    int i = 0;    //1-10錯誤碼的返回返回信息    for(i = 0; i <= 10; i++)    {        printf("%d     %s/n", i, strerror(i));    }    system("pause");    return 0;}

執行結果:?

在實際在使用的時候,錯誤碼并非由我們來控制的,而是接收系統返回的錯誤信息

例2:

#include #include string.h>#include     char *str = strerror(errno);//需引用頭文件errno.h    printf("%s/n", str);    //errno 是一個全局的錯誤碼的變量    //當c語言的庫函數在執行過程中,發生了錯誤,就會把對應的錯誤碼,復制到errno中

例3:

#include #include int main(){    //打開文件    FILE *pf = fopen("test.txt", "r");    if(pf == NULL)    {        printf("%s/n", strerror(errno));//知道錯誤的原因    }    else    {        printf("open file success./n");    }    return 0;}

執行結果:?

六、字符操作

字符分類函數

函數如果他的參數符合下列條件就返回真
iscntrl任何控制字符
isspace空白字符:空格‘ ’,換頁‘/f’,換行"/n",回車‘/r’,制表符"/t"或者垂直制表符"/v"
isdigit十進制數字 0~9
isxdigit十六進制數字,包括所有十進制數字,小寫字母a~f,大寫字母A~F
islower小寫字母a~z
isupper大寫字母A~Z
isalpha字母a~z或A~Z
isalnum字母或者數字,a~z,A~Z,0~9
ispunct標點符號,任何不屬于數字或者字母的圖形字符(可打印)
isgraph任何圖形字符
isprint任何可打印字符,包括圖形字符和空白字符

注:0位假,非0為真


?字符轉換

int tolower ( int c ); //tolower 轉小寫字母int toupper ( int c );//toupper 轉大寫字母

例1:

#include #include int main(){    char ch = tolower("Q");    putchar(ch);    system("pause");    return 0;}

執行結果:?

例2:

#include #include int main(){    //大寫字母轉小寫    char arr[] = "No Mercy";    int i = 0;    while(arr[i])    {        if(isupper(arr[i]))        {            arr[i] = tolower(arr[i]);        }        i++;    }    printf("%s/n", arr);    return 0;}

執行結果:?

七、內存操作函數

在之前的學習中,我們了解了字符串拷貝可以使用strcpy函數,但是strcpy函數具有局限性。

當拷貝的數據不是字符串時,比如說int類型、float類型,還能使用strcpy函數嗎?

strcpy函數在拷貝的時候是以/0為字符串拷貝的結束標志,那么在拷貝其它類型數據的時候,拷貝該結束的時候不一定存在/0。所以使用strcpy函數肯定是行不通的。那怎么辦呢?

此時我們就可以使用memcpy函數-- - 內存拷貝函數,用來拷貝任意類型數據。

memcpy

void *memcpy ( void * destination, const void * source, size_t num );//void* - 通用類型的指針-無類型指針//dest destination 表示內存拷貝的目的位置//src source 表示內存拷貝的起始位置//size_t num 表示內存拷貝的字節數
  • 函數memcpy從source的位置開始向后復制num個字節的數據到destination的內存位置
  • 這個函數在遇到 "/0" 的時候并不會停下來
  • 如果source和destination有任何的重疊,復制的結果都是未定義的。

例:

int main(){    int arr1[] = { 1,2,3,4,5 };    int arr2[5] = { 0 };    memcpy(arr2, arr1, sizeof(arr1));    return 0;}

調試結果:

memcpy函數的模擬實現

void *my_memcpy ( void *dest, const void *src, size_t num) {     void *ret = dest;     assert(dest && src);     while (num--)     {         //*(char*)dest = *(char*)src;		//dest = (char*)dest + 1;//++(char*)dest		//src = (char*)src + 1;//++(char*)src        *((char*)dest)++ = *((char*)src)++;     }     return ret; }int main(){    int arr1[10] = { 1,2,3,4,5,6,7,8,9,10 };	int arr2[10] = { 0 };	my_memcpy(arr2, arr1, 20);    return 0;}

memmove

void * memmove ( void * destination, const void * source, size_t num ); //void* - 通用類型的指針-無類型指針//dest destination 表表示內存移動的目的位置//src source 表示內存移動的起始位置//size_t num 表示移動內存的字節數
  • ?和memcpy的差別就是memmove函數處理的源內存塊和目標內存塊是可以重疊的
  • 如果源空間和目標空間出現重疊,就得使用 比特科技 memmove函數處理

memmove函數的模擬實現

void *my_memmove( void *dest, const void *src, size_t num) {     void * ret = dest;     assert(dest && src);    if (dest <= src || (char *)dest >= ((char *)src + num))     {         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(){    int arr1[10] = {0,1,2,3,4,5,6,7,8,9};    int arr2[10] = {0};    my_memmove(arr1 + 2, arr1, 20);    return 0;}

memset

void* memset(void* dest, int c, size_t count);

作用:Sets buffers to a specified character.(將緩沖區設置為指定的字符)

以字節為內存設置單位

例:

#include#includeint main(){	char arr[] = "abcdefg";	memset(arr, "*", 4);	printf("%s", arr);	return 0;}

執行結果


memcmp

int memcmp ( const void * ptr1,              const void * ptr2,              size_t num ); 
  • 比較從ptr1和ptr2指針開始的num個字節
  • 返回值如下

例:

#include#includeint main(){	int arr1[5] = { 1,2,3,4,5 };	int arr2[5] = { 1,2,3,4,8 };	int ret = memcmp(arr1, arr2, sizeof(arr1));	if (ret > 0)	{		printf("arr1 > arr2");	}	else if (ret == 0)	{		printf("arr1 == arr2");	}	else	{		printf("arr1 < arr2");	}	return 0;}

執行結果:

文章版權歸作者所有,未經允許請勿轉載,若此文章存在違規行為,您可以聯系管理員刪除。

轉載請注明本文地址:http://m.specialneedsforspecialkids.com/yun/118797.html

相關文章

  • C語言進階】??數據類型&amp;amp;&amp;amp;整型在內存中的存儲

    目錄 ? ?一、數據類型介紹 二、類型的意義 三、類型的基本歸類 整型家族 浮點數家族 構造類型(自定義類型) 指針類型 空類型 四、整形在內存中的存儲 原碼、反碼、補碼 大小端字節序 為什么有大端和小端? 一道經典筆試題 ?一、數據類型介紹 數據從大的方向分為兩類: 內置類型自定義類型內置類型我們前面已經學習過,如下: char? ? ? ? ? ? //字符數據類型 short? ? ? ...

    Xufc 評論0 收藏0
  • C語言進階】自定義類型(2)枚舉&amp;amp;聯合

    目錄 一、枚舉 (一)枚舉類型的定義 (二)使用枚舉的原因? (三)枚舉的優點? (四)枚舉的大小 (五)枚舉的使用 二、聯合(共用體) (一)聯合類型的定義 (二)聯合的特點 (三)面試題 (四)聯合大小的計算 一、枚舉 枚舉顧名思義就是:列舉?。? ?即把可能的取值一一列舉出來。 比如我們現實生活中: 一周當中從周一至周日的7天,可以一一列舉;性別有:男、女、保密,可以一一列舉;月份有...

    leiyi 評論0 收藏0
  • JavaScript進階函數和對象知識點詳解

      在過往學習的JavaScript都是在基礎,現在為大家介紹更為深入的JavaScript知識。  JavaScript函數  JavaScript函數和Java函數是有一部分相似的,所以學習起來也會相對簡單  基本構造  1.直接構造  //function代表函數標志,name為函數名稱,參數可有可無   functionname(參數){   //...   return;   }  2....

    3403771864 評論0 收藏0
  • python數學建模Numpy應用介紹與Pandas學習

      小編寫這篇文章的主要目的,主要是來給大家解答下關于python數學建模的一些相關的介紹,涉及到內容涵蓋Numpy的一些相關的應用具體的一些介紹。另外,還會涉及到相關的Pandas學習知識,具體內容下面給大家詳細解答下。  1 Numpy介紹與應用  1-1Numpy是什么  NumPy是一個運行速度非常快的數學庫,一個開源的的python科學計算庫,主要用于數組、矩陣計算,包含:  一個強大的...

    89542767 評論0 收藏0
  • python數學建模之Numpy應用介紹與Pandas學習

      小編寫這篇文章的一個主要目的,主要是來給大家去做一個介紹。介紹的內容主要是關于建模知識的一些相關介紹,包括其Pandas的一些相關學習,就具體的操作內容,下面就給大家詳細解答下。  Numpy學習  1 Numpy介紹與應用  1-1Numpy是什么  NumPy是一個運行速度非常快的數學庫,一個開源的的python科學計算庫,主要用于數組、矩陣計算,包含:  一個強大的N維數組對象ndarr...

    89542767 評論0 收藏0

發表評論

0條評論

最新活動
閱讀需要支付1元查看
<