天天看點

第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章 字元串和格式化輸入

4.2 字元串簡介

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

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

4.2.1 char類型數組和null字元

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

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

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章 字元串和格式化輸入

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

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

注意,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 明示常量

第4章 字元串和格式化輸入
第4章 字元串和格式化輸入
// 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章 字元串和格式化輸入

4.4.1 print()函數

4.4.2 使用print()

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

第4章 字元串和格式化輸入
第4章 字元串和格式化輸入
第4章 字元串和格式化輸入
/* 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 轉換說明

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

第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

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

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.
           
第4章 字元串和格式化輸入
第4章 字元串和格式化輸入
/* 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;
}
           
[[email protected]] 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章 字元串和格式化輸入

4.5 本章小結

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