iT邦幫忙

DAY 15
3

emacs的30天學習筆記系列 第 32

懷舊C語言:1988 The C Programming Language 2nd Edition(PART III)

  • 分享至 

  • xImage
  •  

大師的火力展示,**大師也觀摩別人的code嗎?**1988年C語言成熟度已經達到很高的水平嗎?

在第5章,有很多玄妙的指標寫法:

大師不愧為大師,一個字串複製,寫了4個版本 而且愈寫愈玄。

/* strcpy: copy t to s; array subscript version */
void strcpy(char *s, char *t)
{
int i;
i = 0;
while ((s[i] = t[i]) != '\0')
i++;
}
For contrast, here is a version of strcpy with pointers:
/* strcpy: copy t to s; pointer version */
void strcpy(char *s, char *t)
{
int i;
i = 0;
while ((*s = *t) != '\0') {
s++;
t++;
}
}
In practice, strcpy would not be written as we showed it above. Experienced C programmers would prefer
/* strcpy: copy t to s; pointer version 2 */
void strcpy(char *s, char *t)
{
while ((*s++ = *t++) != '\0')
;
}
As the final abbreviation, observe that a comparison against '\0' is redundant, since the question is merely whether the expression is zero. So the function would likely
be written as
/* strcpy: copy t to s; pointer version 3 */
void strcpy(char *s, char *t)
{
while (*s++ = *t++)
;
}

第一版是陣列版,第二版是指標版,我們可以比較清楚的看出一個字元逐一個字元拷貝的動作。

而第三/四版,表面上看起來是while迴圈,但是在gdb中

(gdb) s
strcpy (s=0x22ff34 "0\032@", t=0x22ff3e "ABCDEFG") at a01.c:67
67 while (*s++ = *t++)
(gdb) n
69 }(gdb) n

直接塞一串字元!!覺得這種寫法不是很容易理解,但是精簡得令人覺得不可思議,且
一步到位。

測試的code是:

#include <stdio.h>

void strcpy(char *s, char *t);
void strcat(char s[], char t[]);

int main()
{
char src[10]="ABCDEFG";
char des[10]="HI";
char *ps;
char *pd;
ps=src;
pd=des;
strcpy(pd,ps);
printf("%s \n",pd); 
printf("%s \n",ps); 

}

在第二章,有一個例子:

/* strcat: concatenate t to end of s; s must be big enough */
void strcat(char s[], char t[])
{
int i, j;
i = j = 0;
while (s[i] != '\0') /* find end of s */
i++;
while ((s[i++] = t[j++]) != '\0') /* copy t */
;
}

最玄妙的是最後一行,有了上面的預防針,當然,也是一步到位。

while ((s[i++] = t[j++]) != '\0') /* copy t */

測試的code如下:

int main()
{
char src[10]="ABCDEFG";
char des[2]="HI";
char *ps;
char *pd;
ps=src;
pd=des;
strcat(ps,pd);
printf("%s \n",pd); 
printf("%s \n",ps); 
}

習題5-3

Exercise 5-3. Write a pointer version of the function strcat that we showed in Chapter 2: strcat(s,t) copies the string t to the end of s.

寫一個指標版的strcat

void strcat(char *s, char *t)
{
int i, j;
i = j = 0;
while ( *(s+i) != '\0') /* find end of s */
i++;
while ((*(s+i++) = *(t+j++)) != '\0') /* copy t */
;
}

筆者覺得這樣比較能理解。對於**while ((*(s+i++) = *(t+j++)) != '\0') /* copy t */
;**這一行總是可以一步到位,覺得很神奇。

因為這樣會讓人想把while拿掉。

拿掉while試試,結果變成

$ a
HI
ABCDEFGH

$ a
HI
ABCDEFGHI

所以while還是有用,拿掉只會做一次。沒拿掉會做多次,只是在gdb trace模式,都是一次!!

筆者把測試code改成。

#include <stdio.h>

void strcpy(char *s, char *t);
void strcat(char s[], char t[]);

int main()
{
char src[30]="ABCDEFG";
char des[10]="HIJKLMNOPQ";
char *ps;
char *pd;
ps=src;
pd=des;
//strcpy(&src,&des);
//strcpy(pd,ps);
strcat(ps,pd);
printf("%s \n",pd); 
printf("%s \n",ps); 


}

這時結果就不如預期,用gdb trace一下,發現:

Program received signal SIGSEGV, Segmentation fault.
0x0040148f in strcat (
s=0x22ff1a "ABCDEFGHIJKLMNOPQABCDEFGHIJKLMNOPQABCDEFGHIJKLMNOPQABCDEFGHIJKLM
NOPQABCDEFGHIJKLMNOPQABCDEFGHIJKLMNOPQABCDEFGHIJKLMNOPQABCDEFGHIJKLMNOPQABCDEFGH
IJKLMNOPQABCDEFGHIJKLMNOPQABCDEFGHIJKLMNOPQABCDEFGHIJKLM"...,
t=0x22ff10 "HIJKLMNOPQABCDEFGHIJKLMNOPQABCDEFGHIJKLMNOPQABCDEFGHIJKLMNOPQABC
DEFGHIJKLMNOPQABCDEFGHIJKLMNOPQABCDEFGHIJKLMNOPQABCDEFGHIJKLMNOPQABCDEFGHIJKLMNO
PQABCDEFGHIJKLMNOPQABCDEFGHIJKLMNOPQABCDEFGHIJKLMNOPQABC"...) at a01.c:41
41 while ((*(s+i++) = *(t+j++)) != '\0') /* copy t */
(gdb)

除錯的過程中,發現

(gdb) p s
$8 = 0x22ff1a "ABCDEFGHIJKLMNOPQAB"
(gdb) p t
$9 = 0x22ff10 "HIJKLMNOPQABCDEFGHIJKLMNOPQAB"
(gdb) p &s
$10 = (char **) 0x22ff00
(gdb) p &t
$11 = (char **) 0x22ff04

0x22ff10 和 0x22ff1a 如果以16進位來說的話,a 是10,會不會是 靠得太近引起的問題??

筆者不死心的一路試下去,發現
是 **char des[13]="HIJKLMNOPQR";**的問題,如果是des[13],不能放13個字元,只能放12個,不然會產生異常,算是筆者耍寶。


上一篇
Web service的好朋友:cURL
下一篇
懷舊C語言:1988 The C Programming Language 2nd Edition(PART IV)
系列文
emacs的30天學習筆記38
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

1 則留言

0
總裁
iT邦好手 1 級 ‧ 2011-11-09 10:39:41

timloo提到:
如果是des[13],不能放13個字元,只能放12個

哈哈這就是str和mem的差別囉,str一定要留個位置來放"\0".

我要留言

立即登入留言