天天看點

memset,memcpy,strcat,strcpy,strncpy,strcmy, strstr總結

size_t和int   

size_t是一些C/C++标準在stddef.h中定義的。這個類型足以用來表示對象的大小。size_t的真實類型與作業系統有關。

在32位架構中被普遍定義為:typedef   unsigned int size_t;

而在64位架構中被定義為:typedef  unsigned long size_t;

size_t在32位架構上是4位元組,在64位架構上是8位元組,在不同架構上進行編譯時需要注意這個問題。而int在不同架構下都是4位元組,與size_t不同;且int為帶符号數,size_t為無符号數。

1.memset

頭檔案:

#include <string.h>

函數原型:

void *memset(void *a, int ch, size_t length);
           

函數說明:

将參數a所指的記憶體區域前length個位元組以參數ch填入,然後傳回指向a的指針。在編寫程式的時候,若需要将某一數組作初始化,memset()會很友善。

實作代碼:

void *memset(void *a, int ch, size_t length)     
{     
    assert(a != NULL);     
    void *s = a;     
    while (length--)     
    {     
        *(char *)s = (char) ch;     
        s = (char *)s + 1;     
    }     
    return a;     
}
           

應用:

#include <iostream>
#include <string.h>
using namespace std;
int main()
{
        char a[3]="my";
        char b[8]="aaaaaaa";
        memset(b,'c',3);
        cout<<b<<endl;
        return 0;
}
           
memset,memcpy,strcat,strcpy,strncpy,strcmy, strstr總結

2.memcpy函數

頭檔案:

#include <string.h>

函數原型:

void *memcpy(void *dst, const void *src, size_t length);
           

函數說明:

從 src 所指的記憶體位址的起始位置開始,拷貝length個位元組的資料到 dest 所指的記憶體位址的起始位置。你可以用這種方法複制任何類型的值(例如:int,double,結構或結構數組),如果src和dst以任何形式出現了重疊,它的結果将是未定義的。

實作代碼:

void *memcpy(void *dst, const void *src, size_t length)
{
    assert((dst != NULL) && (src != NULL));
  char *tempSrc= (char *)src;            //儲存src首位址
  char *tempDst = (char *)dst;           //儲存dst首位址
  while(length-- > 0)                    //循環length次,複制src的值到dst中
         *tempDst++ = *tempSrc++ ;
  return dst;
}
           

含重疊檢測功能的實作:

char *my_memcpy(char *dst, const char* src, int cnt)
{
	if (dst == NULL && src == NULL)
		return nullptr;
	char *ret = dst;
	if (dst >= src && dst <= src + cnt - 1) //記憶體重疊,從高位址開始複制
	{
		dst = dst + cnt - 1;
		src = src + cnt - 1;
		while (cnt--)
			*dst-- = *src--;
	}
	else    //正常情況,從低位址開始複制
	{
		while (cnt--)
			*dst++ = *src++;
	}
	return ret;
}
           

應用:

#include <iostream>
#include <string.h>
using namespace std;
int main()
{
        char a[3]="my";
        char b[8]="aaaaaaa";
        memcpy(b,a,2);
        cout<<b<<endl;
        return 0;
}
           
memset,memcpy,strcat,strcpy,strncpy,strcmy, strstr總結

3.strcat

頭檔案:

#include <string.h>

函數原型:

char *strcat(char *dst, char const *src);
           

函數說明:

strcat 函數要求 dst 參數原先已經包含了一個字元串(可以是空字元串)。它找到這個字元串的末尾,并把 src 字元串的一份拷貝添加到這個位置。如果 src 和 dst 的位置發生重疊,其結果是未定義的。程式設計者需要保證目标字元數組剩餘的空間足以儲存整個字元串。

實作代碼:

char *strcat (char * dst, const char * src)
{
    assert(NULL != dst && NULL != src);   // 源碼裡沒有斷言檢測
    char * cp = dst;
    while(*cp )
         cp++;                      /* find end of dst */
    while(*cp++ = *src++) ;         /* Copy src to end of dst */
    return dst;                  /* return dst */
}
           

注意:while(*cp++ = *src)會拷貝src這個字元串中的'\0',因為是先進行指派,然後判斷while('\0')不滿足。

應用:

#include <iostream>
#include <string.h>
using namespace std;
int main()
{
        char a[3]="my";
        char b[8]="aaaaaaa";
        strcat(a,b);
        cout<<a<<endl;
        return 0;
}
           
memset,memcpy,strcat,strcpy,strncpy,strcmy, strstr總結

4.strcpy

頭檔案:

#include <string.h>

函數原型:

char *strcpy(char *dst, const char *src);
           

函數說明:

函數把參數 src 字元串複制到 dst 參數,dst 字元串的結束符也會複制,如果參數 src 和 dst 在記憶體中出現疊,其結果是未定義的。由于 dst 參數将進行修改,是以它必須是個字元串數組或者是一個指向動态記憶體配置設定的數組指針,不能使用字元串常量。

需要注意的是:程式員必須保證目标字元串數組的空間足以容納需要複制的字元串。如果多餘的字元串比數組長,多餘的字元仍被複制,它們将覆寫原先存儲于數組後面的記憶體空間。

實作代碼:

char *strcpy(char *dst, const char *src)    // 實作src到dst的複制
{
    if(dst == src) return dst;              //源碼中沒有此項
   assert((dst != NULL) && (src != NULL)); //源碼沒有此項檢查,判斷參數src和dst的有效性
  char *cp = dst;                         //儲存目标字元串的首位址
  while (*cp++ = *src++);                 //把src字元串的内容複制到dst下
  return dst;
}
           

記憶體重疊解決代碼

char *Mystrcpy(char *dst, const char *src)
{
	if (dst == src)
		return dst;
	if (dst == NULL && src == NULL)
		return nullptr;
	char *ret = dst;
	int cnt = strlen(src);
	if (ret >= src && ret <= src + cnt - 1) //記憶體重疊,從高位址開始複制
	{
		ret = ret + cnt - 1;
		src = src + cnt - 1;
		while (cnt--)
			*ret-- = *src--;
	}
	else    //正常情況,從低位址開始複制
	{
		while (cnt--)
			*ret++ = *src++;
	}
	return dst;
}
           

注意:while(*cp++ = *src)會拷貝src這個字元串中的'\0',因為是先進行指派,然後判斷while('\0')不滿足。

應用:

#include <iostream>
#include <string.h>
using namespace std;
int main()
{
        char a[3]="my";
        char b[8]="aaaaaaa";
        strcpy(b,a);
        cout<<b<<endl;
        return 0;
}
           
memset,memcpy,strcat,strcpy,strncpy,strcmy, strstr總結

注意:這裡的結果是my而不是myaaaaa,可通過看實作代碼看出端倪,因為拷貝了'\0',是以終止了。

番外:

為什麼strcpy的傳回值是char* ?

有時候函數原本不需要傳回值,但為了增加靈活性如支援鍊式表達,可以附加傳回值。

例如字元串拷貝函數strcpy 的原型:

char *strcpy(char *strDest,const char *strSrc);

strcpy 函數将strSrc 拷貝至輸出參數strDest 中,同時函數的傳回值又是strDest。這樣做并非多此一舉,可以獲得如下靈活性:

char str[20];

int length = strlen( strcpy(str, “Hello World”) );

5.strncpy

頭檔案:

#include <string.h>

函數原型:

char *strncpy(char *dst, char const *src, size_t len);
           

函數說明:

strncpy 把源字元串的字元複制到目标數組,它總是正好向 dst 寫入 len 個字元。如果 strlen(src) 的值小于 len,dst 數組就用額外的 NUL 位元組(C語言中的'\0')填充到 len 長度。如果 strlen(src)的值大于或等于 len,那麼隻有 len 個字元被複制到dst中。這裡需要注意它的結果将不會以NULL位元組結尾。

實作代碼:

char *strncpy(char *dst, const char *src, size_t len)
{
    assert(dst != NULL && src != NULL);     //源碼沒有此項
    char *cp = dst;
    while (len-- > 0 && *src != '\0')
        *cp++ = *src++;
    *cp = '\0';                             //源碼沒有此項
    return dst;
}
           

在安全性方面,顯然strncpy要比strcpy安全得多,strcpy無法控制拷貝的長度,不小心就會出現dest的大小無法容納src的情況,就會出現越界的問題,程式就會崩潰。而strncpy就控制了拷貝的字元數避免了這類問題,但是要注意的是dest依然要注意要有足夠的空間存放src,而且src 和 dest 所指的記憶體區域不能重疊。

6.strcmy

頭檔案:

#include <string.h>

函數原型:

strcmp(const char *s1,const char * s2)
           

函數說明:

C/C++函數,比較兩個字元串。設這兩個字元串為str1,str2,

若str1==str2,則傳回零;

若str1<str2,則傳回負數;

若str1>str2,則傳回正數。

實作代碼:

注意:C語言中'\0'的ascii碼是0

int strcmp(const char *str1, const char *str2)
{
	assert(str1 != NULL && str2 != NULL);
	int ret = 0;
	while (!(ret = *(unsigned char *)str1 - *(unsigned char *)str2) && *str1)
	{
		str1++;
		str2++;
	}
	if (ret < 0)
		return -1;
	if (ret > 0)
		return 1;
	return ret;
}
           

注意:

memset和memcpy可以複制任何内容,而後面的4個是專門用于字元串處理的函數。可以從函數參數看出來。

7.stoi

int myAtoi(string str)
{
	int num = 0;
	int sign = 1;
	int length = str.size();
	int i = 0;
	for (; i < length; ++i)
		if (str[i] != ' ')
			break;
	if (str[i] == '+')
		i++;
	else if (str[i] == '-')
	{
		sign = -1;
		i++;
	}
	for (; i < length; ++i)
	{
		if (str[i]<'0' || str[i]>'9')
			return num*sign;
		if (num > INT_MAX / 10 || (num == INT_MAX / 10 && (str[i] - '0')>INT_MAX % 10))
			return sign == -1 ? INT_MIN : INT_MAX;
		num = num * 10 + (str[i] - '0');
	}
	return sign == -1 ? -num : num;
}
           

8.strstr函數

判斷字元串substr是否是src的子串。注意此函數的傳回值是src中開始比對的那個字元的字元數組。

char* My_strstr(char *src, char *substr)
{
	if (src == nullptr && substr == nullptr)
		return nullptr;
	int len = strlen(src);
	for (int i = 0; i < len; ++i,++src)
	{
		char *p = src;
		for (char *q = substr;; p++, q++)
		{
			if (*q == '\0')
				return src;
			if (*q != *p)
				break;
		}
	}
	return nullptr;
}
           

9.判斷子序列

class Solution {
public:
    bool isSubsequence(string s, string t) {
        int len = s.size();
        int len1 = t.size();
        
        if(len > len1) return false;
        int i = 0,j = 0;
        while(i < len && j < len1)
        {
            if(s[i] == t[j])
            {
                i++;            
            }
            
            j++;
        }
        
        if(i == len) return true;
        return false;
    }
};
           

繼續閱讀