第4章 字符串和格式化輸入

函數:strlen()

關鍵字:const

字符串

如何創建、存儲字符串

如何使用strlen()獲取字符串的長度

用C預處理指令#define和ANSIC的const修修飾符創建符號常量

 

目錄

4.1 前導程序

4.2 字符串簡介

4.2.1 char類型數組和null字符

4.2.2 使用字符串

4.2.3 strlen()函數

4.3 常量和C預處理器

4.3.1 const限定符

4.3.2 明示常量

4.4 printf()和scanf()

4.4.1 print()函數

4.4.2 使用print()

4.4.3 printf()的轉換說明修飾符

4.4.4 轉換說明

4.4.5 使用scanf()

4.4.6 printf()和scanf()的修飾符

4.4.7 printf()的用法提示

4.5 關鍵概念

4.5 本章小結


4.1 前導程序

// talkback.c -- nosy, informative program
#include <stdio.h>
#include <string.h>      // for strlen() prototype
#define DENSITY 62.4     // human density in lbs per cu ft
int main()
{
    float weight, volume;
    int size, letters;
    char name[40];        // name is an array of 40 chars
    
    printf("Hi! What's your first name?\n");
    scanf("%s", name);
    printf("%s, what's your weight in pounds?\n", name);
    scanf("%f", &weight);
    size = sizeof name;
    letters = strlen(name);
    volume = weight / DENSITY;
    printf("Well, %s, your volume is %2.2f cubic feet.\n",
           name, volume);
    printf("Also, your first name has %d letters,\n",
           letters);
    printf("and we have %d bytes to store it.\n", size);
    
    return 0;
}
Hi! What's your first name?
lalalala
lalalala, what's your weight in pounds?
1111
Well, lalalala, your volume is 17.80 cubic feet.
Also, your first name has 8 letters,
and we have 40 bytes to store it.

4.2 字符串簡介

字符串(character string)是一個或多個字符的序列。

“Zing wet the strings of my heart! ”雙引號告知編譯器擴起來的是字符串,正如單引號標識單個字符一樣。

4.2.1 char類型數組和null字符

把字符串中的字符逐個放入數組,計算機處理在末尾加\0的細節。scnf()在讀輸入的時候也完成這項工作的細節,包括define預定義的時候,總之,你不用親自把空字符放在字符串末尾。

4.2.2 使用字符串

/* praise1.c -- uses an assortment of strings */
#include <stdio.h>
#define PRAISE "You are an extraordinary being."
int main(void)
{
    char name[40];
    
    printf("What's your name? ");
    scanf("%s", name);
    printf("Hello, %s. %s\n", name, PRAISE);
    
    return 0;
}

 

What's your name? angela lalala
Hello, angela. You are an extraordinary being.

注意:scanf()只會讀取字符串的第一個單詞,它在遇到第1個空白(空格、製表符、換行符)時就不再讀取輸入了。後面的fgets()函數用於讀取一般字符串

4.2.3 strlen()函數

/* praise2.c */
// try the %u or %lu specifiers if your implementation
// does not recognize the %zd specifier
#include <stdio.h>
#include <string.h>      /* provides strlen() prototype */
#define PRAISE "You are an extraordinary being."
int main(void)
{
    char name[40];
    
    printf("What's your name? ");
    scanf("%s", name);
    printf("Hello, %s. %s\n", name, PRAISE);
    printf("Your name of %zd letters occupies %zd memory cells.\n",
           strlen(name), sizeof name);
    printf("The phrase of praise has %zd letters ",
           strlen(PRAISE));
    printf("and occupies %zd memory cells.\n", sizeof PRAISE);
    
    return 0;
}

What's your name? Serendiapity Chance
Hello, Serendiapity. You are an extraordinary being.
Your name of 12 letters occupies 40 memory cells.
The phrase of praise has 31 letters and occupies 32 memory cells.

string.h頭文件包含多個與字符串相關的函數原型。一般而言,C把函數庫中相關的函數歸爲一類,併爲每類函數提供一個頭文件。

截止到現在接觸到兩個頭文件,stdio.h與string.h

注意,name數組明確告知有40個存儲單元,故第12個單元存儲空字符,strlen()並未將其計入。但是對於PRAISE,sizeof,把字符串末尾不課件的空字符也計算在內,因爲它爲明確告知計算機要給字符串預留多少空間,所以必須計算雙引號的字符數。

sizeof和strlen返回的類型,C99和C11標準專門做了%zd的轉換說明

4.3 常量和C預處理器

#define TAXRATE 0.0012

編譯時替換(complie-time substitution),在運行程序時,所有的替換均已完成,這樣定義的常量稱爲明示常量(manifest constant)

4.3.1 const限定符

const int MONTHS = 12;

const限定變量爲只讀變量

4.3.2 明示常量

// defines.c -- uses defined constants from limit.h and float.
#include <stdio.h>
#include <limits.h>    // integer limits
#include <float.h>     // floating-point limits
int main(void)
{
    printf("Some number limits for this system:\n");
    printf("Biggest int: %d\n", INT_MAX);
    printf("Smallest long long: %lld\n", LLONG_MIN);
    printf("One byte = %d bits on this system.\n", CHAR_BIT);
    printf("Largest double: %e\n", DBL_MAX);
    printf("Smallest normal float: %e\n", FLT_MIN);
    printf("float precision = %d digits\n", FLT_DIG);
    printf("float epsilon = %e\n", FLT_EPSILON);
    
    return 0;
}
Biggest int: 2147483647
Smallest long long: -9223372036854775808
One byte = 8 bits on this system.
Largest double: 1.797693e+308
Smallest normal float: 1.175494e-38
float precision = 6 digits
float epsilon = 1.192093e-07

4.4 printf()和scanf()

輸入/輸出函數 = I/O函數。函數打印數據的指令要與待打印數據的的類型匹配,需要用到轉換說明(conversion specification)

4.4.1 print()函數

4.4.2 使用print()

4.4.3 printf()的轉換說明修飾符

/* width.c -- field widths */
#include <stdio.h>
#define PAGES 959
int main(void)
{
    printf("*%d*\n", PAGES);
    printf("*%2d*\n", PAGES);
    printf("*%10d*\n", PAGES);
    printf("*%-10d*\n", PAGES);
    
    return 0;
}
*959*
*959*  //字段寬度自動擴大以符合整數的長度
*       959*  //7個空格和3位數字,並且數字位於字段右側
*959       *  //
// floats.c -- some floating-point combinations
#include <stdio.h>

int main(void)
{
    const double RENT = 3852.99;  // const-style constant
    
    printf("*%f*\n", RENT);//系統默認值,小數點後6位
    printf("*%e*\n", RENT);//小數點左側1個數字,右側計數法
    printf("*%4.2f*\n", RENT);
    printf("*%3.1f*\n", RENT);
    printf("*%10.3f*\n", RENT);//控制小數點右側顯示位數
    printf("*%10.3E*\n", RENT);
    printf("*%+4.2f*\n", RENT);//前面顯示+號
    printf("*%010.2f*\n", RENT);//0標記使得打印的值前面以0填充以滿足字段要求
    
    return 0;
}
*3852.990000*

*3.852990e+03*
*3852.99*
*3853.0*
*  3852.990*
* 3.853E+03*
*+3852.99*
*0003852.99*
/* flags.c -- illustrates some formatting flags */
#include <stdio.h>
int main(void)
{
    printf("%x %X %#x\n", 31, 31, 31); //十六進制數
    printf("**%d**% d**% d**\n", 42, 42, -42);//在轉換說明中用空格在輸出的正值前面生成前導空格,負值前面不產生前導空格
    printf("**%5d**%5.3d**%05d**%05.3d**\n", 6, 6, 6, 6);//使用精度生成足夠的前導0以滿足最小位數的要求
    
    return 0;
}
1f 1F 0x1f
**42** 42**-42**
**    6**  006**00006**  006**
/* stringf.c -- string formatting */
#include <stdio.h>
#define BLURB "Authentic imitation!"
int main(void)
{
    printf("[%2s]\n", BLURB);//字段擴大爲可容納字符串中的所有字符
    printf("[%24s]\n", BLURB);//精度限制了待打印字符的個數
    printf("[%24.5s]\n", BLURB);
    printf("[%-24.5s]\n", BLURB);//-標記似的文本左對齊輸出
    return 0;
}
[Authentic imitation!]
[    Authentic imitation!]
[                   Authe]
[Authe                   ]

4.4.4 轉換說明

轉換其實是翻譯說明,把給定的值翻譯成十進制整數文本並打印出來

 

/* intconv.c -- some mismatched integer conversions */
#include <stdio.h>
#define PAGES 336
#define WORDS 65618
int main(void)
{
    short num = PAGES;
    short mnum = -PAGES;
    
    printf("num as short and unsigned short:  %hd %hu\n", num,
           num);//336 336
    printf("-num as short and unsigned short: %hd %hu\n", mnum,
           mnum); //-336 65200
    printf("num as int and char: %d %c\n", num, num);// 336 p
    printf("WORDS as int, short, and char: %d %hd %c\n",
           WORDS, WORDS, WORDS);//65618 82 R
    return 0;
}
printf("-num as short and unsigned short: %hd %hu\n", mnum, mnum);

short int的大小爲2字節,其次系統採用二進制補碼來表示有符號整數,0~32767爲本身,32768~65535爲負數,65535爲-1,655334爲-2,65200爲-336

short int是2字節,而char是1字節,所以%c打印336的時候,會進行截斷相當於一個整數除以256,只保留其餘數。在這中情況下餘數是80,對應的ASCII值是字符P。即該數字被解釋成“以256爲模”(modulo 256),即該數字除以256後取其餘數。

65518存儲爲4字節的int類型值,用%hd轉換說明打印時,printf()只使用最後2個字節,相當於65618除以65536的餘數,即餘數是82.

/* floatcnv.c -- mismatched floating-point conversions */
#include <stdio.h>
int main(void)
{
    float n1 = 3.0;
    double n2 = 3.0;
    long n3 = 2000000000;
    long n4 = 1234567890;
    
    printf("%.1e %.1e %.1e %.1e\n", n1, n2, n3, n4); 
//float類型的值作爲printf()參數時會被轉換成double類型,即8字節
    printf("%ld %ld\n", n3, n4);
//正確的轉換說明
    printf("%ld %ld %ld %ld\n", n1, n2, n3, n4);
//轉換說明也會產生虛假的結果
    return 0;
}
3.0e+00 3.0e+00 3.1e+46 1.7e+266
2000000000 1234567890
0 1074266112 0 1074266112

floatcnv.c:10:45: warning: format specifies type 'double' but the argument has type 'long' [-Wformat]
    printf("%.1e %.1e %.1e %.1e\n", n1, n2, n3, n4);
                      ~~~~                  ^~
                      %.1ld
floatcnv.c:10:49: warning: format specifies type 'double' but the argument has type 'long' [-Wformat]
    printf("%.1e %.1e %.1e %.1e\n", n1, n2, n3, n4);
                           ~~~~                 ^~
                           %.1ld
floatcnv.c:12:33: warning: format specifies type 'long' but the argument has type 'float' [-Wformat]
    printf("%ld %ld %ld %ld\n", n1, n2, n3, n4);
            ~~~                 ^~
            %f
floatcnv.c:12:37: warning: format specifies type 'long' but the argument has type 'double' [-Wformat]
    printf("%ld %ld %ld %ld\n", n1, n2, n3, n4);
                ~~~                 ^~
                %f
4 warnings generated.

/* prntval.c -- finding printf()'s return value */
#include <stdio.h>
int main(void)
{
    int bph2o = 212;
    int rv;
    
    rv = printf("%d F is water's boiling point.\n", bph2o);
    printf("The printf() function printed %d characters.\n",
           rv);
    return 0;
}
212 F is water's boiling point.
The printf() function printed 32 characters.
/* longstrg.c –– printing long strings */
#include <stdio.h>
int main(void)
{
    printf("Here's one way to print a ");
    printf("long string.\n");
    printf("Here's another way to print a \
long string.\n");
    printf("Here's the newest way to print a "
           "long string.\n");      /* ANSI C */
    
    return 0;
}
//總之,不能在雙括號括起來的字符串中間斷行
Here's one way to print a long string.
Here's another way to print a long string.
Here's the newest way to print a long string.

4.4.5 使用scanf()

// input.c -- when to use &
#include <stdio.h>
int main(void)
{
    int age;             // variable
    float assets;        // variable
    char pet[30];        // string
    
    printf("Enter your age, assets, and favorite pet.\n");
    scanf("%d %f", &age, &assets); // use the & here
    scanf("%s", pet);              // no & for char array
//變量加&,字符數組不使用&
    printf("%d $%.2f %s\n", age, assets, pet);
    
    return 0;
}
Enter your age, assets, and favorite pet.
38
92360.88 llama
38 $92360.88 llama

Enter your age, assets, and favorite pet.
  42

      323。45
42 $323.00 。45

//scanf()函數使用空白把輸入分成多個字段。在依次把轉換說明和字段匹配時跳過空白。

scanf()根據一個%d轉換說明讀取一個整數,每次跳過所有空白字符,直至遇到第一個非空白字符纔開始讀取,並尋找數字字符或者符號,便保存該字符,並讀取下一個字符。不斷地讀取和保存字符,直至遇到非數字字符,如果遇到了非數字字符,它便認爲讀到了整數的末尾。

scanf()能讀取不同類型的數據。把更多字符識別成數字的一部分,浮點轉換要求scanf()識別小數點、e計數法。

scanf("%d,%d",&n,&m)
88,121
88,
121

4.4.6 printf()和scanf()的修飾符

/* varwid.c -- uses variable-width output field */
#include <stdio.h>
int main(void)
{
    unsigned width, precision;
    int number = 256;
    double weight = 242.5;
    
    printf("Enter a field width:\n");
    scanf("%d", &width);
    printf("The number is :%*d:\n", width, number);
    printf("Now enter a width and a precision:\n");
    scanf("%d %d", &width, &precision);
    printf("Weight = %*.*f\n", width, precision, weight);
    printf("Done!\n");
    
    return 0;
}
Enter a field width:
6
The number is :   256:
Now enter a width and a precision:
8 3
Weight =  242.500
Done!
/* skiptwo.c -- skips over first two integers of input */
#include <stdio.h>
int main(void)
{
    int n;
    
    printf("Please enter three integers:\n");
    scanf("%*d %*d %d", &n);
    printf("The last integer was %d\n", n);
    
    return 0;
}
[wlsh@wlsh-MacbookPro] Ch04$ ./a.out 
Please enter three integers:
2013 2014 2015
The last integer was 2015

4.4.7 printf()的用法提示

printf("%d %d %d\n",val1,val2,val3);
12 234 1222
4 5 23
22334 2322 10001

printf("%9d %9d %9d\n",val1,val2,val3);
12    234   1222
 4      5     23

4.5 關鍵概念

4.5 本章小結

 

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章