在學習字元串的時候,我們常常會遇到一些相關功能的函數用于字元串,是問題變得簡單:這些函數在c語言庫函數中存在,我們直接使用就可以了;不過在一些面試中我們常常會被要求模拟實作這些函數;是以知道這些函數的實作過程還是有必要的:以下是本人在學習中總結的一些常用的字元串操作函數的模拟實作過程和一些使用例題:
1.strcpy的實作:将一個字元串拷貝到另一個字元串上面,不受限制,以"\0"作為結束标志。'\0'也要拷貝進去。
功能實作:
char * strcpy(char *dest,const char*src)
{
char *ret=dest;
assert(dest);
assert(src);
while(*dest++=src++)
{
;
}
return ret;
}
....................................................................................................................
2.strncpy的實作:受限制的字元串複制操作函數,想複制幾個就複制幾個,以複制個數作為結束标志。
函數實作:
char * strcpy(char *dest,const char*src,size_t n) // size_t:無符号整型
{
char *ret=dest;//儲存目标字元串的位址;作為傳回指針;
assert(dest);
assert(src);
while(n--&&*src)
{
*dest++=*src++;
}
if(count>0)
{
while(count--)
{
*dest++='\0';//如果源字元串字元個數少于拷貝的字元數,則超出的字元用'\0'代替;
}
}
return ret;
}
注意:當n很大的時候;例如是100w,這個時候該怎麼優化程式才能使拷貝的更快一點?
回答:源程式中為*dest++=*src++; 一次src隻讀一個字元然後寫入dest;我們可以使src一次讀4個字元,
然後寫給dest;當最後剩下的字元少于4個,然後再一個一個讀出寫入。
....................................................................................................................
3.strcat:不受限制的字元串追加函數,整體字元串全部追加到另一個字元串後面,以"\0"作為結束标志。
函數實作:
char * strcpy(char *dest,const char*src)
{
char *ret=dest;
assert(dest);
assert(src);
while(*dest)
{
dest++;
}
while(*src)
{
*dest++=*src++;
}
return ret;
}
....................................................................................................................
4.strncat:受限制的字元串追加函數,想追加幾個追加幾個,以追加個數n作為接受标志。
char * strncat(char *dest,const char*src,size_t n)
{
char *ret=dest;
assert(dest);
assert(src);
while(*dest)
{
dest++;
}
while(n--)
{
*dest++=*src++;
}
*dest='\0';
return ret;
}
....................................................................................................................
測試代碼:
#include<stdio.h>
#include<stdlib.h>
#include<assert.h>
int main()
{
char arr1[20]="abcd";
char arr2[]="efgh";
char* ret= strncat(arr1,arr2,3);//注意此處測試不同的函數,函數名要改變
printf("%s",ret);
return 0;
}
....................................................................................................................
....................................................................................................................
5.将0,1,2,3,4,5,6,7,8,9逆序儲存并輸出;
功能實作:
void Nixu(int arr[],int n)
{
int* left=arr;//char*p1=&arr[0]
int* right=&arr[n-1];
while(left<right)
{
int tmp=*left;
*left=*right;
*right=tmp;
left++;
right--;
}
}
int main()
{
int arr[]={0,1,2,3,4,5,6,7,8,9};
int i=0;
int sz=sizeof(arr)/sizeof(arr[0]);//不能用strlen()在功能函數内部求字元數組長度;
//因為傳進去的arr[]數組代表數組首元素的位址;
//更不能用sizeof()在功能函數内部求字元數組大小;規定的;
Nixu(arr,sz);
for(i=0;i<sz;i++)
{
printf("%d",arr[i]);
}
return 0;
}
....................................................................................................................
6.分别用指針和數組兩種方式對是十數字由大到小進行排序:
功能實作:
void Maopao(int arr[],int n)
{
int i=0;
int sign=0;
for(i=0;i<n-1;i++) // 比較趟數,每次回來一趟下一次兩兩比較的時候少一個數;
{
int j=0;
sign=1;
for(j=0;j<n-1-i;j++) //兩兩比較
{
while(arr[j]>arr[j+1])
{
int tmp=arr[j];
arr[j]=arr[j+1];
arr[j+1]=tmp;
sign=0;
}
}
if(sign==1)
break;
}
}
int main()
{
int arr[]={1,9,7,6,5,3};
int i=0;
int sz=sizeof(arr)/sizeof(arr[0]);
Maopao(arr,sz);
for(i=0;i<sz;i++)
{
printf("%d ",arr[i]);
}
}
注意:以上隻是很簡單普遍的一種冒泡排序,這個程式還可以繼續優化;
可以怎麼優化呢:例如當一個數組的數字是8,7,6,1,2,3,4,5,我們其實隻需要三趟就可以得到排序好的數組;
因為當經過三次循環形成1 2 3 4 5 6 7 8 9時,就不必繼續循環下去再去讓剩下的數兩兩比較了,此時我們
可以定義一個标志符sign,每次進入第一層循環以後檢查一下它的值,我自己規定當sign=0時繼續比較;
當sign=1時,說明沒有進入兩兩比較的循環,此時剩下的資料的順序本來就是從小到大的順序,故跳出循環,排序完成。
....................................................................................................................
7.strcmp的實作:無限制條件,比較整個字元串大小。
程式實作:
#include<stdio.h>
#include<string.h>
#include<assert.h>
int my_strcmp(const char*arr1,const char*arr2)
{
assert(arr1);
assert(arr2);
while(*arr1==*arr2)
{
if(*arr1=='\0')
return 0;
arr1++;
arr2++;
}
return *arr1-*arr2;
}
int main()
{
char arr1[]="bbcdef";
char arr2[]="bbcdef";
int ret=my_strcmp(arr1,arr2);
if(ret==0)
{
printf("arr1=arr2");
}
else if(ret>0)
{
printf("arr1>arr2");
}
else
{
printf("arr1<arr2");
}
}
....................................................................................................................
8.模拟實作strncmp:有限制,比較前n個字元的大小;
功能實作:
#include<stdio.h>
#include<string.h>
#include<assert.h>
int my_strcmp(const char*arr1,const char*arr2,size_t n)
{
assert(arr1);
assert(arr2);
while(n--)
{
while(*arr1==*arr2)
{
if(*arr1=='\0')
return 0;
arr1++;
arr2++;
}
return *arr1-*arr2;//if (*arr1-*arr2>0)
} //return 1;
} //else return 0;
int main()
{
char arr1[]="bbcfef";
char arr2[]="bbcdef";
int ret=my_strcmp(arr1,arr2,4);
if(ret==0)
{
printf("arr1=arr2");
}
else if(ret>0)
{
printf("arr1>arr2");
}
else
{
printf("arr1<arr2");
}
}
....................................................................................................................
9.模拟實作strlen:(遇到'\0'停止計數,不包含'\0').
功能實作:
#include<stdio.h>
int my_strlen(char*str)
{
int count=0;
while(*str!='\0')
{
count++;
str++;
}
return count;
}
int main()
{
char str[]="abcdef";
int ret=my_strlen(str);
printf("%d",ret);
return 0;
}
....................................................................................................................
10.模拟實作strstr:strstr(str1,str2) 函數用于判斷字元串str2是否是str1的子串。
如果是,則該函數傳回str2在str1中首次出現的位址;否則,傳回NULL。
功能實作:
#include<stdio.h>
#include<string.h>
char *mathed(const char*str,const char*substr)
{
const char*str1=str;
const char*str2=substr;
const char*start=NULL;
while(*str1)
{
start=str1;
while(*str1==*str2&&*str1&&str2)
{
str1++;
str2++;
}
if(*str2=='\0')
return (char*)start;
str1=start-1;
str2=substr;
}
return NULL;
}
int main()
{
char str1[]="abcdef";
char str2[]="de";
char*ret=mathed(str1,str2);
printf("%s",ret);
return 0;
}
ok!!!come on!!!