7-變量與格式化輸出
我們已經用 C 語言進行過一些輸出,這一節,我們將核心討論變量與格式化輸出。
其實printf函數名由兩個部分組成,第一個部分是表示“打印”,而第二部分就是這個——它表示了英文中的“格式(format)”的縮寫,說明這個函數在打印信息的時候是可以帶有格式的。
printf函數 printf--->打印(print) 格式(format)
而這里說的格式,就是我們在前面課程中學到過的printf函數的第一個參數。如果我們不嵌入任何的變量,那么這個格式就是純粹的一個字符串;如果我們需要在字符串中嵌入一些變量,那么我們嵌入占位符后printf函數的第一個參數就會被視為我們所需要的“格式”。
在 C 語言中,我們常用的基礎變量數據類型有:
|
數據類型 |
關鍵字 |
說明 |
|
整數型 |
int |
反映機器中整數的自然長度 |
|
字符型 |
char |
占1字節,可存一個字符 |
|
單精度浮點數型 |
float |
用于存儲精度的實數 |
|
雙精度浮點數型 |
double |
用于存儲雙精度的實數,平時更常用 |
除了基礎變量數據類型,我們還可以在基本數據類型的前面加一些限定符,比方說short和long可以加在int、float、double前用于修飾對應的數據類型。比方說,被short修飾的整數型變量的存儲位數會更小,相應的可存整數范圍也就比較小,而如果被long修飾則會用更多的存儲位數,能存的整數范圍也不小于int。
我們還可以用unsigned來修飾int,說明數據類型是無符號的整數。當你寫下unsigned int的時候,你其實在告訴計算機“這個整數不需要留出一位來存儲符號,所有的位數都可以拿來存數字”。相應的,這種類型的變量就可以用于表示更大的正整數。
你可能注意到了,老師一直在強調不同數據的類型。因為,不同類型的變量只能和符合它類型的值相對應。如果我們試圖將一個10000000000 存到一個int類型的變量d中的時候,由于存儲的位數不夠,這個變量d就無法正確地存儲這個數或將它用于計算了(如果數據比較大,其實可以學習用一下long long int的數據類型,具體做法可以自己在互聯網上找一找喔)。
接下來,讓我們來回顧一下我們之前用到過的格式化輸出。
printf("%c is %dst letter", alpha, number);
在這里,第 1 個占位符%c用于給char類型的第1 個變量alpha做占位符,而第2 個占位符%d用于給int類型的第2 個變量number做占位符。
針對其它數據類型,占位符應該是什么呢?
|
數據類型及顯示 |
占位符 |
占位符來源單詞首字母 |
示例數據 |
|
有符號整數型 |
%d或%i |
digit和integer |
-392 |
|
字符型 |
%c |
character |
A |
|
無符號整數型 |
%u |
unsigned |
392 |
|
浮點型 |
%f或%F |
float |
39.2 |
|
雙精度浮點數 |
%lf |
double |
39.200000 |
|
科學計數法浮點數 |
%e或%E |
exponent |
3.9256e+2 |
|
實數(不顯示無意義0) |
%g或%G |
|
39.2和1.2e+02 |
|
內存地址 |
%p |
pointer |
b8000000 |
|
字符串 |
%s |
string |
sample |
8-1在程序中學會換行
不知道你有沒有在讀前面的內容和寫代碼的過程中發現一些規律?我們是不是經常在程序的時候按回車鍵換行?
我們為什么在程序中換行呢?哪些地方需要換行呢?哪些地方被建議換行呢?
在回答列出的這些問題之前,先讓我們來看一個同學的代碼:
1#include <stdio.h>
2 int main() {
3 int number;
4 char alpha;
5 // 在上面聲明了兩個變量,請在下面給他們賦值
6 number = 1;alpha = 'A';printf("%c is %dst letter", alpha, number);
7
8 return 0;
9 }
是不是覺得這個代碼很眼熟?沒錯,這就是你之前也學習過的課程中的代碼。
可是,你有沒有覺得這個代碼寫的很難看呢?這個同學把兩個變量的賦值和格式化輸出全都寫在了一行里面了!這么長的內容讀起來實在很難受。
那么,讓老師帶你一起看看,在寫程序的時候,有哪些地方必須要換行呢?
·定義函數之前
·除了小括號內的分號后
·左大括號后
·右大括號前(除列表形式進行初始化的時候)
·右大括號后(除 struct,enum 的定義體后,else 前、do-while 的 while 前、初始化列表)
·單行超過 80 字符的最后一個 token 前
·不換行導致不符合語法(宏定義最后)
如果在你弄懂所有上面描述的情況后,遇到上述情況時你都能正確地進行換行,你會獲得一個看起來舒服很多的程序。
比如對于之前那份代碼,如果我們按照上一個要求進行一下修改,我們將得到:
1 #include <stdio.h>
2 int main() {
3 int number;
4 char alpha;
5 // 在上面聲明了兩個變量,請在下面給他們賦值
6 number = 1;
7 alpha = 'A';
8 printf("%c is %dst letter", alpha, number);
9
10 return 0;
11 }
除了必須換行的地方,還有一些地方,你可以選擇性的換行:
·單行的代碼塊之前
·左大括號前
·列表形式進行初始化時的右大括號前
·部分右大括號后(僅 struct,enum 的定義后,else 前、do-while 的 while 前)
·switch 的 case 和 default 的冒號后
·enum 定義的逗號后
·兩塊邏輯不相關的代碼段之間
也有一些地方,老師會建議你不要換行,比方說:
·連續的兩個空行如果出現可以減少一個換行
·正常的兩個關鍵詞間未被建議換行的地方
對于我們說的可以換行和不建議換行的情況,我們可以在變量賦值后加上一個空行,然后把return 0;前的兩行空行變成一個空行。
1#include <stdio.h>
2int main() {
3 int number;
4 char alpha;
5 // 在上面聲明了兩個變量,請在下面給他們賦值
6 number = 1;
7 alpha = 'A';
8
9 printf("%c is %dst letter", alpha, number);
10
11 return 0;
12}
這樣我們的代碼就會更清晰一些,也看得更舒服一些啦。這里說的一些需要換行的場景你可能還沒有學到,在之后遇到時,如果不確定要不要換行,記得回來看一看。
1-重新認識基本運算
在 C 語言中,也有我們很熟悉的四則運算的 運算符(operator):
·加法:使用加號+作為運算符,例如a + b。
·減法:使用減號-作為運算符,例如a - b。
·乘法:區別于我們平時手寫的乘號“×”,C 語言中我們使用*作為乘號,例如a * b表示a與b相乘。
·除法:區別于我們小時候寫的除號“÷”和寫分式時的“—”,在 C 語言中我們使用/作為除號,例如a / b表示a被b除。
除了我們熟悉的加、減、乘、除,在我們的 C 語言中,我們還有一種運算—— 求余(complementation) 運算(也稱 模運算(modulo operation) )。顧名思義,求余運算,就是求兩個整數相除以后的余數。
如果我們要求 21 除以 4 的余數,我們會得到 1。
在 C 語言中,我們用%作為求余運算的運算符,可以寫成例如a % b的形式。對于上面的例子,我們可以直接寫21 % 4——這個運算式的值將會是 1。
不知道你發現了沒有,我們在這里提到的所有的算術運算符,無論是加、減、乘、除還是求余,在運算符的前、后各有一個被用于運算過程的值,我們稱這種運算符為雙目運算符(binary operator)。
我們之前學習賦值的時候學到的=賦值運算符,也是一個雙目運算符。

我們可以將賦值運算符和這一塊的算術運算符結合,得到一些有意思的表達:

·number = 1 + king;表示數值 1 加上變量king內的值作為一個運算式,這個運算式的值被賦值給變量number。
·number = king * queen;表示將變量king內的值乘以變量queen內的作為一個運算式,這個運算式的值被賦值給變量number。
·number = number + 1;表示將變量number內的值加上數值 1 作為一個運算式,這個運算式的值被賦值給number。
通過變量、數值和運算符構成的結果是可以連寫的,我們寫a = 1 + 2 + 3這樣的形式,可以被理解成1 + 2的運算結果通過加法運算符再次和 3 進行了加法,整體被看作一個運算式,這個運算式的值被賦值給了a。但是,如果我們寫b = 1 + 2 * 3,則表示 1 通過加法運算符和2 * 3的運算結果進行了加法,整體被看作一個運算式,這個運算式的值被賦值給了b。
為什么會有這樣的差異呢?學過數學的你一定不會覺得很奇怪,如數學中的運算一樣,C 語言的基本運算符也是有優先級的,乘法、除法、求余(模運算)的優先級比加法、減法要更高。
如果我們想改變這種優先級,C 語言中也設計了一種和數學中教的一模一樣的工具——小括號。如果你希望1 + 2的運算結果通過乘法運算符和3 進行乘法,并把結果賦值給b,那么我們需要把運算過程寫成b = (1 + 2) * 3。

2-做一下簡單的運算
#include <stdio.h>
int main() {
int a;
a = 12;
printf("%d",a+19);
return 0;
}
3-a的n次方
在這里,我們給出來了一小段初始化代碼,里面聲明了兩個變量a和n,并且給他們進行了賦值。
我們今天的任務是求a的n次方。我們會用到一個叫pow的函數(這里的函數名稱來自于英文中次方的單詞“power”)。當我說“用”的時候,你是不是很開心?因為明顯它是一個庫里已經實現的函數,你可以拿來“用”!所以呢,你需要在main函數開始之前引入一下包含了pow函數的數學庫,它對應的頭文件為math.h。

#include <stdio.h>
#include <math.h>
int main() {
double a;
double n;
a = 2.0;
n = 4.0;
// 在下面打出來 a 的 n 次方的結果
return 0;
}
引入了數學庫以后,我們就可以使用pow函數了。
pow函數接受兩個參數,第一個參數需要傳入的是我們的底數a,第二個參數傳入的是我們的冪數n。
請注意,我們通過pow得到的結果將是一個浮點數,所以我們講pow(a,n)的結果通過printf輸出出來的時候,占位符要用%lf(注意是字母:l和f,另外別多在第一個參數中寫其他東西哦),你自己寫一下?
printf("%lf",pow(a,n));
你可以試試改改a和n的值,然后再點擊運行,看看結果會不會有什么不同呢?
紅色是自己加入到代碼!!!
#include <stdio.h>
#include <math.h>
int main() {
double a;
double n;
a = 2.0;
n = 4.0;
// 在下面打出來 a 的 n 次方的結果
printf("%lf",pow(a,n));
return 0;
}
結果:16.0
4-數學函數
在 C 語言的數學(math)函數庫中,有很多不同的數學函數,我們會在這里對其中一部分進行介紹。
之前已經我們已經學習了冪函數 pow,今天讓我們一起來再學習一下絕對值函數、三角函數、對數函數、取整函數、平方根函數這些數學函數在 C 語言中的使用。

絕對值函數(absolute value function)
在 C 語言中有兩個常用的絕對值函數,分別是abs函數和fabs函數(這里的函數名稱來自于英文中單詞 “absolute”)。
其中abs函數傳入的參數需要是一個整數,返回的結果則會是這個傳入的整數求完絕對值以后的結果。例如,abs(-4)的返回值會是 4。
而fabs函數,就明顯是一個起名很友好的函數,其中f表示了浮點數。所以呢,它很自然的就是一個類似于abs函數,但是傳入的參數是浮點數,返回結果是浮點數求完絕對值以后結果的函數。例如,fabs(-3.14)的返回值會是3.14,fabs(2.7)的返回值會是 2.7。

不同于其他大多數數學函數,abs使用前需要引入stdlib.h,引入后abs就可以使用了。
三角函數(trigonometric function)
在 C 語言的數學庫中,包含了我們常用的三角函數:正弦sin、余弦cos、正切tan、反正弦asin、反余弦acos、反正切atan。它們都接受一個(雙精度)浮點數值作為傳入的參數,返回的則是對應的數學定義上的三角函數被應用在傳入的浮點數值后的結果,類型也是(雙精度)浮點數。
例如,tan(3.1415926535/4)的返回值是 1.000000,acos(0.32696)的返回值是1.237711。

對數函數(logarithmic function)
對于以 e 為底的對數函數lnx,C 語言的數學庫中提供了名為log的函數;對于以10 為底的對數函數,數學庫中則提供了一個名為log10的函數。
與三角函數類似,它們都接受一個(雙精度)浮點數值作為傳入的參數,返回的也都是對應的數學定義上的相應對數函數被應用在傳入的浮點數值后的結果,類型也是(雙精度)浮點數。
例如,log(2.71828)的返回值是 0.999999,而log10(100)的返回值是 2.000000。

取整函數
在數學庫中還有 四舍五入函數(rounding function)、上取整函數(或天花板函數,ceiling function)和 下取整函數(或地板函數,floor function)。它們接受一個(雙精度)浮點數值作為傳入的參數,返回的也都是對應的數學定義上的相應上、下取整后的浮點數結果。例如,floor(2.7)返回的是小于或等于2.7 的整數,也就是 2.000000,ceil(-3.2)返回的是大于或等于?3.2 的整數,也就是?3.000000。

平方根函數
另外,數學庫中還有一個 平方根函數(square root function) 。它接受一個(雙精度)浮點數值作為傳入的參數,返回的也都是對應的數學定義上的浮點數結果。例如,sqrt(42.25)的結果會是6.500000。
接下來的課程中,我們可就要試著使用這些數學函數了喔!

5-讓C語言編程計算器

接下來讓我一起把y的結果值輸出出來。你應該知道怎么做吧?在這老師和你約定,用”%g”(實數格式占位符)作為格式化輸出的第一個參數值。
#include <stdio.h>
#include <math.h>
int main() {
double y;
y = sqrt((1-cos(0.5))/2);
printf("%g",y);
return 0;
}
輸出結果:0.247404
計算球的體積





#include <stdio.h>
#include <math.h>
#define PI 3.14
int main() {
double radius;
radius = 12.0;
printf("%g",4.0/3*PI*pow(radius,3));
return 0;
}
輸出結果:7234.56
6-在程序中添加注釋
在前面的課程中,我們看到一些給出的代碼中一些//以開頭的內容,這些以開頭的內容是一種用于解釋說明的信息,我們稱之為 注釋(comment) 。
在代碼比較長、或者程序設計的邏輯比較復雜的時候,我們就需要為程序寫一些注釋了。在 C 語言中,一共有兩種注釋的方式——第一種是我們已經看到的在某一行中插入的形式,這行中,后的所有內容將在程序編譯時被忽略,成為僅被程序員所關注的內容。我們將這種形式的注釋稱為 行注釋(line comment) 。

在 C 語言中,還有另一種注釋——以/*作為開頭,以*/作為結尾。在一對與之間的所有內容都會被作為注釋的內容,只讓程序員作為參考,而在程序編譯時不被關注。我們將這種形式的注釋稱為 塊注釋(block comment) 。
行注釋和塊注釋的目的其實都是一樣的,老師在課程代碼中寫一些注釋,可以幫助你了解如何更好的學會程序。你寫一些注釋可以讓自己在之后回顧時不至忘記自己的想法,也可以讓和你一起寫程序的其它程序員更容易的看懂你的程序。

你可能會好奇:既然有兩種不同的注釋,什么時候用塊注釋,什么時候用行注釋呢?
一般來說,對于以下兩種情況下,我們會使用塊注釋:
·需要把一大段代碼暫時性注釋掉的時候
·使用一些會讀取代碼中塊注釋來生成文檔的工具的時候
除了以上的兩種情況,我們都建議大家使用行注釋,哪怕是連續的幾行文字,我們都依然建議你分成多個連續行注釋來進行說明,而不是使用一個跨多行的塊注釋。

你是不是有些懷疑老師的說法?來讓我帶你來看一個多行注釋寫法可能造成的問題。
1 int main() {
2 printf("Hello") ;/* 說你好 */
3 printf("World");
4 return 0;
5 }
對于上面給出的情況,如果我們需要暫時性注釋掉main函數內的前兩行代碼,我們將得到一個這樣的代碼片段:
1 /*
2 printf("Hello") /* 說你好 */
3 printf("World");
4 */
這種情況下,第一個printf開始前的/*和“說你好”后的*/將會被匹配。而編譯器將無法正常的對之后的一個*/進行理解。這種問題是不是我們不希望出現的呢?如果我們平時都用單行注釋,是不是就不會有這樣的問題了呢?

我是第一次寫博客,如果有什么缺失之處,還希望廣大朋友們,多多指正。

浙公網安備 33010602011771號