1.字符串比較
int strcmp(const char *s1, const char *s2);
比較兩個字符串的大小(不忽略大小寫),返回值很有學問:如果s1小於s2返回一個小於0的數,如果s1大於s2返回一個大於0的數,如果相等則返回0。返回值是兩個字符串中第一個不相等的字符ascii碼的差值。實現如下:
[cpp] view plaincopyprint?
int my_strcmp(const char *s1, const char *s2){ //important! validate arguments first! assert(NULL !=s1 && NULL != s2); while(*s1 != '\0' && *s2 != '\0' && *s1==*s2){ s1++; s2++; } return *s1 - *s2; }
注意再函數開始進行參數檢查,防止輸入參數有NULL時發生運行時錯誤。
strcmp是最常用的字符串比較函數,一般用法是if(!strcmp(s1, s2)){ ...}。如果不是對整個字符串進行比較而只是比較指定數目的字符串,可以使用函數:
int strncmp(const char *s1, const char *s2, size_t n);
用法和返回值都和strcmp類似,之比較給定字符串的前n個字符,或者到遇到任一字符串結尾。實現如下:
[cpp] view plaincopyprint?
int my_strncmp(const char *s1, const char *s2, size_t n){ //important! validate arguments first! assert(NULL!=s1 && NULL!=s2); if(n == 0) return 0; size_t cnt = 1; while(*s1 != '\0' && *s2 != '\0' && *s1==*s2 && cnt < n){ s1++; s2++; cnt++; } return *s1 - *s2; }需要注意的除了參數檢查外,還要注意n=0的特殊情況,這裡我們n=0永遠返回0。
還有其他一些帶特殊要求字符串比較函數,如:
stricmp,memcmp,memicmp等等,加i表示比較時忽視大小寫,帶mem的是比較一塊內存區間。
2.字符串查找
最簡單的是查找字符串查找字符:
char *strchr(const char *s, int c);
至於參數為什麼是int,歷史遺留問題,這裡不多討論。函數返回在s中找到的第一個c的位置的指針,注意的是,字符串末尾的‘\0’也是可以被查找的。實現如下:
[cpp] view plaincopyprint?char *my_strchr(const char *s, int n){ assert(s != NULL); char c = (char)n; do{ if(*s == c) return (char *)s; }while(*s++); return NULL; }還有查找字符串的函數strstr:
char *strstr(const char *s1, const char *s2);
函數返回s2在s1中出現的首字符的位置,實現如下:
[cpp] view plaincopyprint?char *my_strstr(const char *s1, const char *s2){ assert(NULL!=s1 && NULL!=s2); size_t len = strlen(s2); while(*s1){ if(!strncmp(s1,s2,len)) return (char *)s1; s1++; } return NULL; }
c標准庫中並沒有定義類似strnchr和strnstr的限定查找范圍的函數,當然需要的話我們可以自己定義,如:
[cpp] view plaincopyprint?char *strnstr(const char* s1, const char* s2, size_t n) { const char* p; size_t len = strlen(s2); if (len == 0) { return (char *)s1; } for (p = s1; *p && (p + len<= buffer + n); p++) { if ((*p == *token) && (strncmp(p, token, tokenlen) == 0)) { return (char *)p; } } return NULL; }3.字符串復制
最常見的字符串復制函數是strcpy:
char *strcpy(char *dst, const char *src);
把src所指的由NULL結尾的字符串復制到由dst所指的字符串中,src和dst不可以相同(可以由c99的restrict關鍵字聲明),dst必有足夠的空間存放復制的字符串。
還有一點要注意的是函數返回值,返回值是指向dst的指針,這樣做的目的是方便程序中語句內聯,比如strlen(strcpy(s,t))。
函數的實現如下:
[cpp] view plaincopyprint?char *my_strcpy(char *dst, const char *src){ assert(NULL!=dst && NULL!=src); char *p = dst; while((*dst++ = *src++) != '\0'); return p; }
使用strcpy是危險的,因為函數本身是不檢查dst指向的空間是否足夠存儲需要復制的字符串,導致的一個潛在隱患就是字符串溢出。這也是上個世紀常被黑客利用的一個經典漏洞。所以,在大多數情況下都是用strncpy無疑更加保險:
[cpp] view plaincopyprint?char *my_strncpy(char *dst, const char *src, size_t n){ assert(NULL!=dst && NULL!=src); char *p = dst; while(n){ if((*dst++ = *src++) == '\0') break; n--; } return p; }
需要注意另外一個函數strdup:
char *strdup(const char *);
該函數和strcpy的不同是,函數會自己申請內存空間存放拷貝的字符串,然後返回指向該字符串的指針。所以在使用strdup函數時需要注意的是,在使用完復制的字符串後使用free函數釋放其占用的空間。
另memcpy函數和strncpy類似,只是不會再遇到NULL時終止拷貝,該函數一定會拷貝n個字符。
4.字符串連接
字符串連接是把一個字符串的頭連接到另一個字符串的結尾。
char *strcat(char *s1, const char *s2);
函數的實現如下:
[cpp] view plaincopyprint?char *my_strcat(char *s1, const char *s2){ assert(NULL!=s1 && NULL!=s2); char *p =s1; while(*s1)s1++; strcpy(s1,s2); return p; }
同樣,strcat也是不安全的,因為也對緩沖區足夠存放連接的字串進行了假設。所以,多數情況下我們應該使用更安全的:
char *strncat(char *s1, const char *s2, size_t n
-------------------------------------
歸類自己需要的資料,慢慢爬行
/*========================================================
對於一個五位數a1a2a3a4a5,可將其拆分為三個子數:
sub1=a1a2a3
sub2=a2a3a4
sub3=a3a4a5
例如,五位數20207可以拆分成
sub1=202
sub2=020(=20)
sub3=207
現在給定一個正整數K,要求你編程求出10000到30000之間所有滿足下述條件的五位數,
條件是這些五位數的三個子數sub1,sub2,sub3都可被K整除。
輸入
輸入由鍵盤輸入,輸入僅一行,為正整數K(0<K<1000)。
輸出
輸出到文件,輸出文件的每一行為一個滿足條件的五位數,要求從小到大輸出。
不得重復輸出或遺漏。如果無解,則輸出“No”。
樣例
num.in
15
num.out
22555
25555
28555
30000
==========================================================*/
#include <stdio.h>
#include <string.h>
/*從字符串的左邊截取n個字符*/
char * left(char *dst,char *src, int n)
{
char *p = src;
char *q = dst;
int len = strlen(src);
if(n>len) n = len;
/*p += (len-n);*/ /*從右邊第n個字符開始*/
while(n--) *(q++) = *(p++);
*(q++)='\0'; /*有必要嗎?很有必要*/
return dst;
}
/*從字符串的中間截取n個字符*/
char * mid(char *dst,char *src, int n,int m) /*n為長度,m為位置*/
{
char *p = src;
char *q = dst;
int len = strlen(src);
if(n>len) n = len-m; /*從第m個到最後*/
if(m<0) m=0; /*從第一個開始*/
if(m>len) return NULL;
p += m;
while(n--) *(q++) = *(p++);
*(q++)='\0'; /*有必要嗎?很有必要*/
return dst;
}
/*從字符串的右邊截取n個字符*/
char * right(char *dst,char *src, int n)
{
char *p = src;
char *q = dst;
int len = strlen(src);
if(n>len) n = len;
p += (len-n); /*從右邊第n個字符開始*/
while(*(q++) = *(p++));
return dst;
}
void main()
{
FILE * p;
int i,k,outi,count=0;
int sub1,sub2,sub3;
char *strsub1,*strsub2,*strsub3,*strtempnum,*a,*b,*c;
if((p = fopen("num.out", "ab+")) == NULL)
{
printf("open file fail!");
getch();
exit();
}
printf("Please input int number(0<K<1000):");
scanf("%d",&k);
for(outi=10000;outi<=30000;outi++)
{
itoa(outi,strtempnum,10);
left(strsub1,strtempnum,3);
mid(strsub2,strtempnum,3,1);
right(strsub3,strtempnum,3);
/*
a=strsub1;
b=strsub2;
c=strsub3;
printf("strsub1=%s,strsub2=%s,strsub3=%s\n",a,b,c);
*/
sub1=atoi(strsub1);
sub2=atoi(strsub2);
sub3=atoi(strsub3);
/*
printf("sub1=%d , sub2=%d , sub3=%d \n\n",sub1,sub2,sub3);
printf("sub1k=%d , sub2k=%d , sub3k=%d \n\n" , sub1 % k,sub2 % k,sub3 % k);
getch();
*/
if((sub1%k)==0 && (sub2%k)==0 && (sub3%k)==0)
{
fprintf(p,"%d\n",outi);
count++;
printf("outi=%d\n",outi);
}
else
{
fprintf(p,"%s\n","NO");
}
}
printf("Count=%d OK",count);
fclose(p);
getch();
}
http://www.cnblogs.com/rosesmall/archive/2012/03/27/2420335.html
strcat(字符串1,字符串2)
char s1[10]={"abc"}
char s2[3]={"def"}
printf("%s",strcat(s1,s2))
輸出就是: abcdef
strcpy(p+strlen(q),r);表示從數組首地址偏移strlen(q),也就是從元素d所在的位置開始復制
這時復制完後數組p的長度為3+5=8(元素d被覆蓋)
strcat(p,q);表示從數組p的尾部進行連接,這時數組p的長度為8+3=11
而數組p在定義為char p[20],即請求連續開辟20個char類型存儲單元,而每個char占一字節,所以sizeof(p)等於20
還有問題嗎