C Primer Plus(第6版)第十一章複習題答案
11.12複習題
- 下面字串的宣告有什麼問題?
int main(void)
{
char name[] = {'F', 'e', 's', 's'}; //少了‘\0‘
char name[] = {'F', 'e', 's', 's', '\0'}; //改正後
//當然也可以是用字串字面量進行初始化陣列,這種方式比標準初始化方法簡便的多
char name[] = "Fess";
}
- 下面的程式會列印什麼?
#include <stdio.h> int main(void) { char note[] = "See you at the snack bar."; char * ptr; ptr = note; puts(ptr); //See you at the sanck bar. puts(++ptr); //ee you at the sanck bar. note[7] = '\0'; puts(note); //See you puts(++ptr); //e you return 0; }
結果,
- 下面 程式會列印什麼?
#include <stdio.h> #include <string.h> int main(void) { char food[] = "Yummy"; char * ptr; //順便提醒一下,永遠不要解引用未初始化的指標 ptr = food + strlen(food); //ptr指向'\0' while (--ptr >= food) //先遞減後使用,直至首地址 puts(ptr); //列印結果應該為: return 0; } y my mmy ummy Yummy
猜想結束,我們來驗證下:
#include <stdio.h> #include <string.h> int main(void) { char goldwyn[40] = "art of it all "; char samuel[40] = "I read p"; const char * quote = "the way through."; strcat(goldwyn, quote); strcat(samuel, goldwyn); puts(samuel); return 0; } // 猜測:i read part of it all the way through.
我們來執行試試看:
Bingo!
- 下面的練習設計字串、迴圈、指標和遞增指標。首先定義了下面的函式:
#include <stdio.h>
char *pr(char *str)
{
char *pc;
pc = str;
while (*pc)
putchar(*pc++);
do {
putchar(*--pc);
} while (pc - str);
return (pc);
}
考慮下面的函式呼叫:x = pr("Ho Ho Ho!");
a. 將列印什麼?
答:Ho Ho Ho!!oH oH oH
b. x是什麼型別?
答:指向char型別的指標
c. x的值是什麼?
答:'H’的地址
d. 表示式*- -pc是什麼意思?與 - -*pc有何不同?
答:相當於 *(- -pc),- -(*pc)的區別,前者是先使用指標解引用後遞減指標的值,後者是先解引用指標的值後遞減指標指向的地址的值的大小(例如H變為G)
e. 如果用 *- -pc 替換 - -*pc,會列印什麼?
答:會列印Ho Ho Ho!沒了
原因是:列印完Ho Ho Ho!後pc指向末尾的空字元,此時- -*pc解引用空字元(空字元的值是0)再- -0得到-1,putchar(-1),ASCII碼中沒有對應的字元,所以不再螢幕上輸出
執行結果如圖:
這裡的題目翻譯有錯,檢視原英文
What would be printed if *–pc were replaced with *pc-- ?
用 *pc–替換 *–pc會發生什麼
分析: pc此時指向末尾的空字元,列印空字元然後判斷while迴圈測試條件繼續列印列印!直到列印到o後,pc遞減為首元素的地址,此時pc- str為0跳出while迴圈,
所以列印結果如下圖所示:
f. 兩個while迴圈用來測試什麼?
答:第一個入口測試條件while使得當指標指向字串末尾的空字元時,停止迴圈體
第二個出口測試條件do while中的條件(pc - str)使得當pc指向字串首元素時停止迴圈體
g. 如果pr()函式的引數是空字串,會怎樣?
答:第一個while迴圈不會列印任何東西。第二個while迴圈:指標指向空字元前面的位置,將該位元組解釋成一個字元並列印,重複,永遠都不會滿足條件pc-str=0(pc==str),所以這個 過程會一直持續下去
執行結果如圖:後兩行是CodeBlocks下執行自帶的
h. 必須在主調函式中做什麼,才能讓pr()函式正常執行?
答:必須再主調函式中定義一個指向字串的指標如:char * pt;
並且要給pr()傳遞一個指向char型別的指標如: pt = pr("String");
(Ps:字元常量是指標)
-
假設有如下宣告
char sign = '$';
sign佔用多少位元組的記憶體?'$'
佔用多少位元組的記憶體?"$"
佔用多少位元組的記憶體?
答:sign是char型別的變數,char被定義為1個位元組,'$'
注意字元常量時儲存為int型別,所以通常佔2或4位元組(不同系統),"$"
是字串末尾有空字元,所以佔2個位元組(一個位元組儲存’$‘的編碼,一個位元組儲存’\0’的編碼)。 -
下面的程式會打印出什麼?
#include <stdio.h>
#include <string.h>
#define M1 "How are ya, sweetie? "
char M2[40] = "Beat the clock.";
char * M3 = "chat";
int main(void)
{
char words[80];
printf(M1); //這行也列印How are ya, sweetie?
puts(M1); //How are ya, sweetie?
puts(M2); //Beat the clock.
puts(M2 + 1); //eat the clock.
strcpy(words,M2); //
strcat(words, " Win a toy.");
puts(words); //Beat the clock Win a toy.
words[4] = '\0';
puts(words); //Beat
while (*M3)
puts(M3++); //chat 換行 hat 換行 at 換行 at 換行 t
puts(--M3); //t
puts(--M3); //at
M3 = M1;
puts(M3); //How are ya, sweetie?
return 0;
}
/*
預測列印的結果如下:
How are ya, sweetie?How are ya, sweetie?
Beat the clock.
eat the clock.
Beat the clock. Win a toy.
Beat
chat
hat
at
t
t
at
How are ya, sweetie?
*/
程式執行結果如圖:
8. 下面的程式會打印出什麼?
#include <stdio.h>
int main(void)
{
char str1[] = "gawsie"; // plump and cheerful
char str2[] = "bletonism";
char *ps;
int i = 0;
for (ps = str1; *ps != '\0'; ps++)
{
if ( *ps == 'a' || *ps == 'e') //如果*ps等於字元a或e列印a或e,
putchar(*ps);
else //否則列印該字元ASCII碼減一對應的字元
(*ps)--;
putchar(*ps);
}
putchar('\n');
while (str2[i] != '\0' ) //遍歷直到末尾
{
printf("%c", i % 3 ? str2[i] : '*');//下標是3的倍數列印*字元,否則列印本身*
++i;
}
return 0;
}
/*
預測輸出:
faavrhee
*le*on*sm
*/
執行結果如圖所示:
- 本章定義的s_gets()函式,用指標表示法代替陣列表示法便可減少一個變數i,請改寫該函式。
char * s_gets(char * st, int n)
{
char * ret_val;
int i = 0;
ret_val = fgets(st, n, stdin);
if (ret_val)
{
while (st[i] != '\n' && st[i] != '\0')
i++;
if (st[i] == '\n')
st[i] = '\0';
else
while (getchar() != '\n')
continues;
}
return ret_val;
}
用指標表示法改寫
char * s_gets(char * st, int n)
{
char * ret_val ;
ret_val = fgets(st, n, stdin);
if (ret_val)
{
while (*ret_val != '\n' && *ret_val != '\0')
ret_val++;
if (*ret_val == '\n')
*ret_val = '\0';
else
while (getchar() != '\n')
continue;
}
return ret_val;
}
- strlen()函式接受一個指向字串的指標作為引數,並返回該字串的長度。請編寫一個這樣的函式。
int strlen(const char * st)
{
int ct = 0;
while (*st++)
ct++;
return ct;
}
- 本章定義的s_gets()函式,可以使用strchr()函式代替其中while迴圈來查詢換行符。請改寫該函式。
#include <stdio.h>
#include <string.h>
char * s_gets(char * st, int n)
{
char * ret_val;
char * find;
ret_val = fgets(st, n, stdin);
if (ret_val)
{
find = strchr(st, '\n'); //返回'\n'所在的地址
if (find)
*find = '\0';
else
while (getchar() != '\n')
continue;
}
return ret_val;
}
- 設計一個函式,接受一個指向字串的指標,返回指向該字串第1個空字元的指標,或如果未找到空格字元,則返回空指標。
char * strch(char * st)
{
while (*st != ' ' && *st != '\0')
st++;
if (*st == ' ')
return st;
else return null;
}
下面是第二種方案,可以防止函式修改字串,但是允許使用返回值改變字串。表示式(char *)string被稱為“通過強制型別轉換取消const”
#include <stdio.h> // 提供NULL的定義
char * strblk(const char * st)
{
while (*st != ' ' &7 *st != '\0')
st++;
if (*st == '\0')
return NULL;
else
return (char *)st;
}
- 重寫程式清單11.21,使用ctype.h標頭檔案中的函式,以便無論使用者選擇大寫還是小寫,該程式都能正確答案。
#include <stdio.h>
#include <string.h>
#include <ctype.h>
#define SIZE 40
#define ANSWER "GRANT"
char * s_gets(char * st, int n);
void ToUpper(char * st);
int main(void)
{
char try[SIZE];
puts("Who is buried in Grant's tomb?");
s_gets(try, SIZE);
while (strcmp(try, ANSWER) != 0)
{
puts("No, that's wrong. Try again.");
s_gets(try, SIZE);
}
puts("That's right!");
}
char * s_gets(char * st, int n)
{
char * ret_val;
int i = 0;
ret_val = fgets(st, n, stdin);
ToUpper(ret_val);
if (ret_val)
{
while (ret_val[i] != '\0' && ret_val[i] != '\n')
i++;
if (ret_val[i] == '\n')
ret_val[i] = '\0';
else
while (getchar() != '\n')
continue;
}
return ret_val;
}
void ToUpper(char * st)
{
while (*st)
{
*st = toupper(*st);
st++;
}
}