一、scanf家族
char *p = strrchr(buf,'\n');
*p = '\0'; //去除回車符
if(sscanf(buf,"%d%d%d",&a,&b,&c) != 3)
{
a = 1; //defalut value of a
if(sscanf(buf,"%d%d",&b,&c) != 2)
{
b = 1; //default value of b
if(sscanf(buf,"%d",&c)!=1)
{
printf("input error\n ");
exit(1);
}
}
}
printf("a = %d\nb=%d\nc=%d\n",a,b,c);
sscanf("3.42","%lf",&b); //將字符串轉換為數值double
sprintf(buf,"%.2f",a); //將double型數值轉換為字符串
printf("b = %.2f\n",b);
printf("buf is:%s\n",buf);
}
1、scanf家族的原型
int scanf(char const *format,...);
int fscanf(FILE *stream,char const *format,...);
int sscanf(char const *buffer,char const *format,...);
每個原型中的省略號表示一個可變長度的指針列表。從輸入轉換而來的值逐個存儲到這些指針指向的內存位置。由於C的參數傳遞都是傳值調用決定了可變參數都是指針列表。注意:若給的不是指針,而是變量值。scanf將把變量值當做指針,在進行解引用時或者導致程序終止,或者導致不可預料的內存位置的數據被改寫。
2、返回值
當格式化字符串format到達末尾或者讀取的輸入不再匹配格式字符串所指定的類型時,輸入就停止,並返回被轉換的輸入值的數目,若在任何輸入都沒被轉換之前文件就到達尾部則返回EOF。
3、類型的匹配
由於scanf是采用可變參數的機制,所以函數無法驗證它們的指針參數是否為正確的類型,所以函數假定它們是正確的,(因此格式字符必須和后面的指針指向的類型保持一致)如果指針參數的類型和輸入數據的類型不匹配則結果值就是垃圾。而且鄰近的變量也有可能被改寫。例如:
float a;
scanf("%d",&a); //本來a是一個float數據,卻用一個整形指針指向變量a。
4、scanf格式代碼
format字符串中包括以下內容。
空白字符:他們與輸入中的零個或多個空白字符匹配,在處理過程中將被忽略。(常用於%c中)
格式代碼:他們指定函數如何解釋接下來的輸入字符。
其他字符:若出現其他字符時,下一個輸入字符必須與之匹配。若匹配則該輸入字符丟棄,若不匹配,函數不再讀取,直接返回。
格式代碼:以%開頭,后面接:一個可選的星號;一個可選的寬度;一個可選的限定符;格式代碼
(1)星號:轉換后的值被丟棄而不進行存儲,跳過不需要的輸入字符。
(2)寬度:限制被讀取用於轉換的輸入字符的個數。若未給出寬度,函數讀入字符直到遇到空白字符。
(3)限定符:修改有些格式代碼的含義。注意轉換所有的short、long、double、long double時都要加上限定符。若未加上將導致一個較長的變量只有一部分被初始化,一個較短的變量的鄰近變量也被修改。這些取決於機器中類型的長度。
格式碼\限定符 | h | l | L |
d,i,n | short | long | |
o,u,x | unsigned short | unsigned long | |
e,f,g | double | long double |
例如:short var_a;
scanf("%hd",&var_a);
(4)格式碼:單個字符,表示輸入字符如何被解釋,以及指針列表指針的指向類型。
代碼 | 對應的指針參數類型 | 含義 |
c | char * | 讀取和存儲單個字符,前導的空白字符不跳過(可以在格式字符串中加入空格來跳過)。若給出寬度,就讀取和存儲這個數目的字符,后面不會添加NUL,必須保證足夠大的數組空間 |
i d |
int * | 有符號整數被轉換。%d解釋為十進制。%i根據第一個字符決定值的基數,和整型字符值常量的表示形式相同。10,034,0xa2 |
u o x |
unsigned * | 無符號整數被轉換。u:十進制;o:八進制;x:十六進制 |
e f g |
float * | 期待一個浮點值。他的形式必須像一個浮點型字面值常量,但小數點並不必須 |
s | char * | 讀取一串非空白字符,當發現空白時則輸入停止。后面自動加上NUL。必須保證足夠大的數組空間 |
n | int * | 處理字符的個數 |
5、用scanf實現行定向的輸入。
由於scanf把回車也當做空白字符處理所以使用scanf保持行邊界的同步時很困難的。為了實現行定向。可以搭配fgets。先用fgets讀取一行,然后用sscanf對讀取的行處理。
6、使用sscanf處理可變格式的輸入。
int a,b,c;
fgets(buf,20,stdin);
char *p = strrchr(buf,'\n');
*p = '\0'; //去除回車符
if(sscanf(buf,"%d%d%d",&a,&b,&c) != 3)
{
a = 1; //defalut value of a
if(sscanf(buf,"%d%d",&b,&c) != 2)
{
b = 1; //default value of b
if(sscanf(buf,"%d",&c)!=1)
{
printf("input error\n ");
exit(1);
}
}
}
printf("a = %d\nb=%d\nc=%d\n",a,b,c);
二、printf家族
1、原型
int printf(char const *format,...);
int fprintf(FILE *stream,char const *format,...);
int sprintf(char *buffer,char const *format,...);
2、類型匹配
printf函數和scanf一樣,無法驗證一個值是否具有格式碼所表示的正確類型。所以保證他們相互匹配是程序員的責任。
3、printf格式碼
format字符串包含格式碼,它使參數列表的下一個值根據指定的方式進行格式化,對於其他的字符則原樣輸出。
格式碼由一個%開頭,后邊可以跟:
標志字符、字段寬度、精度、修改符、#標志、格式碼
(1)標志字符:
標志 | 含義 |
- | 左對齊;默認右對齊 |
0 | 右對齊時,用0填充左邊未使用的列;默認用空格填充 |
+ | 當一個數為正數時,前面加上一個+號,默認不顯示 |
空格 | 當一個數為正數時,前面加上一個空格,默認不顯示 |
(2)字段寬度:指定輸出的最小字符數,若輸出的小於字段寬度。則根據標志字符進行相應的修改輸出
(3)精度:
作用於%s:指定要被轉換的最多字符數
作用於%f:指定出現在小數點后的數字位數
(4)修改符:
修改符 | 作用對象 | 表示類型 |
h | d,i,o,u,x | short型整數 |
l | d,i,o,u,x | long型整數 |
l | e,f,g | long double型數據 |
(5)格式代碼
代碼 | 參數 | 含義 |
c | int | 參數被裁剪為unsigned char類型並作為字符打印 |
d i |
int | 作為一個十進制整數打印 |
o u x |
unsigned int | 參數作為一個無符號值打印,u使用十進制,o使用八進制,x使用十六進制 |
e、f、g | double | 參數按照浮點數打印,精度缺少為6位 |
s | char * | 打印一個字符串 |
n | int * | 打印字符的個數 |
(6)#標志
#標志可以作用於格式代碼:o,x,e,f,g 也就是無符號數和浮點數
o:產生的值以0開頭;x:以0x開頭;(這兩個很實用。)
e,f,g:確保結果始終包含一個小數點即使后面沒有數字。
long double a = 3.14;
printf("a = %08.3lf",a); //右對齊,開頭補零,字符寬度8位,精度3位,以long double型輸出。
三、利用sprintf和scanf實現字符串和數值的相互轉換
利用sscanf可以實現字符串向數值的轉換,而利用sprintf實現數值向字符串的轉換
#include<stdio.h>
int main()
{
float a = 3.14;
double b;
int main()
{
float a = 3.14;
double b;
char buf[20];
sprintf(buf,"%.2f",a); //將double型數值轉換為字符串
printf("b = %.2f\n",b);
printf("buf is:%s\n",buf);
}
另外標准庫提供的用於字符串轉換為整型/浮點型的函數有:
int atoi(char const *string);
long int atol(char const *string);
long int strtol(char const *string,char **unused,int base);
long int strtoul(char const *string,char **unused,int base);
double atof(char const *string);
double strtod(char const *string,char **unused);
使用注意事項:
1、跳過前導空白字符,忽略非法綴尾字符
2、對於整型,當base=0時,根據string的字面確定string的進制。(八進制(以0開頭)、十進制(默認)、十六進制(以0x開頭));
3、若不能轉換為相應類型則返回0
4、unused指向無法轉換的字符的指針的指針。
四、通過sprintf獲取一個整數的位數
通常對於一個整數data,我們需要獲得其位數的方法為:對其與10、100、1000、等相除來確定共有多少位。
下面程序提供了一個獲取data位數的一個好方法:
int number,data;
data = 12345;
char buf[20];
sprintf(buf,"%d%n",data,&number); //利用snprintf防止訪問內存越界:snprintf(buf,20,"%d%n",data,&number);
printf("data is %d,has %d characters\n",data,number);
data = 12345;
char buf[20];
sprintf(buf,"%d%n",data,&number); //利用snprintf防止訪問內存越界:snprintf(buf,20,"%d%n",data,&number);
printf("data is %d,has %d characters\n",data,number);
利用printf的%n格式符記錄打印字符的個數來統計data的位數。