C語言對於Android開發來講仍是很是必要的,無論你是要閱讀源碼,仍是想要學習NDK,音視頻,性能優化等,都不可避免須要接觸到C,並且C語言屬於系統級的語言,操做系統內核都有C的身影,因此我今天學習一下C語言,本篇博客做爲筆記,以防之後忘記java
C語言最初適用於系統開發工做的,特別是組成操做系統的程序,因爲C語言產生的代碼運行速度與彙編編寫的代碼運行速度幾乎相同,因此採用C語言做爲系統開發語言,下面列舉幾個使用C的實例編程
寫在源文件的中代碼,使咱們人類能夠看懂的,他須要編譯轉換爲機器語言,這樣CPU能夠按照指令執行程序,而C語言能夠經過GUN編譯器,把源碼編譯爲機器語言數組
Mac上直接下載Xcode就可使用GUN編譯器,開發工具可使用CLion
或者直接用文本編譯器
緩存
#include <stdio.h>
int main() {
/* 個人第一個 C 程序 */
printf("第一個c程序Hello, World! \n");
return 0;
}
複製代碼
一個C程序包括性能優化
#include <stdio.h>
是預處理指令,告訴C編譯器實際編譯以前須要包括stdio.h
文件int main()
是主函數,程序從這裏開始運行,printf()
是程序中另外一個可用的函數做用是在屏幕上顯示Hello, World!
return 0;
標識此函數結束,並返回0Hello, World!
Last login: Mon Feb 17 14:53:00 on ttys002
L-96FCG8WP-1504:~ renxiaohui$ cd Desktop/
L-96FCG8WP-1504:Desktop renxiaohui$ cd c/
L-96FCG8WP-1504:c renxiaohui$ gcc hello.c
L-96FCG8WP-1504:c renxiaohui$ a.out
第一個c程序 Hello, World!
L-96FCG8WP-1504:c renxiaohui$
複製代碼
標記符是用來標記變量,函數或者任何用戶自定的變量名稱,一個標識符以字母A—Z,a-z,或者_下劃線開始,後面跟0個或多個字母,數字,下劃線bash
標識符中不容許出現標點字符,好比@%,標識符是區分大小寫的網絡
這些關鍵字不能做爲常量名或者變量名,其餘標識符的名稱編輯器
關鍵字 | 說明 |
---|---|
continue | 結束當前循環,開始下一輪循環 |
switch | 用於開關語句 |
case | 開關語句分支 |
default | 開關語句中的其餘分支 |
break | 跳出當前循環 |
do | 循環語句的循環體 |
while | 循環語句的循環條件 |
if | 條件語句 |
else | 條件語句否認分支與if一塊兒使用 |
for | 一種循環語句 |
goto | 無條件跳轉語句 |
return | 子程序返回語句,可帶參數可不帶參數 |
char | 聲明字符變量或者返回值類型 |
double | 聲明雙精度浮點類型對象或函數返回值類型 |
float | 聲明浮點型變量或返回值類型 |
short | 聲明短整形變量或者返回值類型 |
int | 聲明整形變量或者返回值類型 |
long | 聲明長整形變量或返回值類型 |
unsigned | 聲明無符號類型變量或返回值類型 |
void | 聲明函數無返回值或無參數,聲明無類型指針 |
enum | 聲明枚舉類型 |
static | 聲明靜態變量 |
auto | 自動聲明變量 |
const | 定義常量,若是一個變量被const修飾,則它的值不能被改變 |
extern | 聲明變量或函數在其餘文件或本文件的其餘位置定義 |
register | 聲明寄存器變量 |
signed | 聲明有符號類型的變量 |
sizeof | 計算數據類型或變量的長度 |
struct | 聲明結構體類型 |
union | 聲明共用體 |
typedef | 給數據類型取別名 |
volatile | 說明變量在執行過程當中能夠隱含的改變 |
能夠看到70%都是java中有的,學習起來並非很難ide
C中的數據類型能夠分爲如下幾種函數
類型 | 描述 |
---|---|
基本數據類型 | 他們是算術類型,包含倆種類型,整數類型和浮點數類型 |
枚舉類型 | 他們也是算術類型,被用來定義在程序中只能賦予其必定的離散整數值得變量 |
void | 標識沒有可用的值 |
派生類型 | 他包括指針類型,數組類型,結構類型,共用體類型和函數類型 |
咱們先介紹基本數據類型
類型 | 存儲大小 | 值範圍 |
---|---|---|
char | 1字節 | -128-127或0-255 |
unsigned char | 1字節 | 0-255 |
signed char | 1字節 | -128-127 |
int | 2或4字節 | -32,768 到 32,767 或 -2,147,483,648 到 2,147,483,647 |
unsigned int | 2或4字節 | 0 到 65,535 或 0 到 4,294,967,295 |
short | 2字節 | -32,768 到 32,767 |
unsigned short | 2字節 | 0 到 65,535 |
long | 4字節 | -2,147,483,648 到 2,147,483,647 |
unsigned long | 4字節 | 0 到 4,294,967,295 |
各種型的儲存大小,與系統位數有關,爲了獲得準確大小能夠用sizeof
來計算
#include <stdio.h>
#include <limits.h>
int main(){
printf("int 存儲大小 : %lu \n", sizeof(int));
return 0 ;
}
複製代碼
int 存儲大小 : 4
複製代碼
類型 | 存儲大小 | 值範圍 | 精度 |
---|---|---|---|
float | 4字節 | 1.2E-38 到 3.4E+38 | 6 位小數 |
double | 8字節 | 2.3E-308 到 1.7E+308 | 15位小數 |
long double | 16字節 | 3.4E-4932 到 1.1E+4932 | 19位小數 |
類型 | 描述 |
---|---|
函數返回爲空 | C 中有各類函數都不返回值,或者您能夠說它們返回空。不返回值的函數的返回類型爲空。例如 void exit (int status); |
函數參數爲空 | C 中有各類函數不接受任何參數。不帶參數的函數能夠接受一個 void。例如 int rand(void); |
指針指向void | 類型爲void*指針表明對象的地址,而不是類型,例如,內存分配函數 void *malloc( size_t size ); 返回指向 void 的指針,能夠轉換爲任何數據類型。 |
變量是程序可操做的儲存區名稱,C中每一個變量都有特定的類型,類型決定了變量的大小和佈局,該範圍內的值均可以儲存在內存中
C語言中有基本數據類型的變量,也能夠有其餘類型的變量,好比數組,指針,枚舉,結構體,共用體等
變量的定義就是告訴儲存器何處建立變量的儲存,以及如何建立變量的儲存,變量定義指定數據類型,幷包含該類型的一個或多個變量列表
type variable_list;
複製代碼
type必須是一個有效的C數據類型,variable_list爲變量的名字,能夠有多個
int i, j, k;
char c, ch;
float f, salary;
double d;
複製代碼
上方i,j,k等聲明並定義了變量i,j,k
變量能夠在聲明的時候初始化
type variable_name = value;
例如
extern int d = 3, f = 5; // d 和 f 的聲明與初始化
int d = 3, f = 5; // 定義並初始化 d 和 f
byte z = 22; // 定義並初始化 z
char x = 'x';
複製代碼
變量的聲明,像編輯器保證變量以指定的類型和名稱存在,這樣編輯器就能夠在不知道變量完整細節的狀況下,也能進一步編譯
變量聲明有倆種狀況
extern int i; //聲明,不是定義
int i; //聲明,也是定義
複製代碼
常量是固定的值,在程序期間不會改變,這些固定的值又叫作字面量
常量能夠是任何基本數據類型,常量在值定義以後不會修改
在C中有倆種定義常量的方式
#define
預處理器#define identifier value
#include <stdio.h>
#include <limits.h>
#define FFF 10
#define DDD 20
#define HHH '\n'
int main(){
int a ;
a =FFF*DDD;
printf("值,%d",a);
printf("\n字符串,%c",HHH);
return 0 ;
}
複製代碼
值,200
字符串,
複製代碼
const
關鍵字const type variable = value;
int main() {
const int FFF =10;
const int DDD=20;
const char HHH='\n';
int a;
a = FFF * DDD;
printf("值,%d", a);
printf("\n字符串,%c", HHH);
return 0;
}
複製代碼
值,200
字符串,
複製代碼
儲存類定義C中變量,函數的範圍和生命週期,這些說明符放在他們所修飾的類型以前,下面列出可用的儲存類
auto儲存類是全部局部變量默認的儲存類
{
int mount;
auto int month;
}
複製代碼
上面的兩種寫法都是同樣的,auto只能用在函數內,即只能修飾局部變量
用於定義儲存在寄存器中而不是RAM的局部變量,這意味着變量的最大大小是寄存器的大小
{
register int miles;
}
複製代碼
寄存器只用於須要快速訪問的變量,好比計數器
編譯器在聲明週期內保持保持局部變量的值,而不須要每次進入和離開做用域是建立和銷燬,所以使用static修飾局部變量,能夠函數調用間保持局部變量的值
static也能夠用於全局變量,當static修飾全局變量時,變量的做用域會限制在他的本文件中,也就是隻有本文件才能夠訪問(普通的全局變量,使用extern外部聲明後任何文件均可以訪問)
static函數:和上方的全局變量同樣(非靜態函數能夠在另外一個文件中直接引用,甚至沒必要使用extern聲明)
用於提供一個全局變量的引用,全局變量對全部的程序文件均可見
當在A文件定義一個全局變量a,B文件想要使用A文件的變量a,能夠在B文件使用extern關鍵字拿到a的引用
第一個文件
#include <stdio.h>
int count =5;
extern void add();
int main() {
add();
return 0;
}
複製代碼
第二個文件
#include <stdio.h>
extern int count;
void add(){
printf("count=%d\n",count);
}
複製代碼
運行後
bogon:untitled renxiaohui$ gcc text.c tex1.c
bogon:untitled renxiaohui$ a.out
count=5
複製代碼
同java,不在記錄
同java
同java
return_type function_name( parameter list ) {
body of the function
}
複製代碼
一個函數的組成部分
return_type
是一個函數返回值的數據類型,有些函數不返回數據,這種狀況下return_type
的關鍵字是void
function_name
int Max(int num1,int num2){
int result;
if(num1>num2){
result=num1;
}else{
result=num2;
}
return result;
}
複製代碼
這就是一個函數的簡單實例
函數的聲明會告訴編譯器,函數的名稱和如何調用函數,函數的實際主體能夠單獨定義
函數聲明包括如下幾個部分
return_type function_name( parameter list );
複製代碼
針對上方的函數咱們能夠聲明
int Max(int num1,int num2);
複製代碼
在函數聲明中,參數名稱並非很重要,能夠省略掉
int Max(int ,int);
複製代碼
當你在一個源文件定義一個函數,在另外一個文件調用這個函數時,函數聲明是必要的,這種狀況下,你須要在調用函數文件的頂部聲明函數
#include <stdio.h>
int Max(int,int);
int main() {
int num1 = 100;
int num2 = 120;
int rec;
rec = Max(num1,num2);
printf("比較結果爲%d\n",rec);
return 0;
}
int Max(int num1, int num2) {
int result;
if (num1 > num2) {
result = num1;
} else {
result = num2;
}
return result;
}
複製代碼
結果爲
比較結果爲120
複製代碼
在某個函數塊內聲明的變量爲局部變量,他只能被該函數或者該代碼塊內的函數語句使用,局部變量外部是不可知的
#include <stdio.h>
int main () {
/* 局部變量聲明 */
int a, b;
int c;
/* 實際初始化 */
a = 10;
b = 20;
c = a + b;
printf ("value of a = %d, b = %d and c = %d\n", a, b, c);
return 0;
}
複製代碼
這裏的a,b,c 都是局部變量
全局變量定義在函數的外部,一般是程序的頂部,全局變量在整個程序的生命週期內都是有效的,在任意的函數內部能夠訪問全局變量。
全局變量能夠被任意函數訪問,也就是說全局變量在聲明後在整個程序中都是可用的
局部變量和全局變量名稱能夠相同,可是在函數內,若是倆個名字相,會使用局部變量,不會使用全局變量
#include <stdio.h>
//全局變量
int a = 10;
int c = 40;
int main(){
//局部變量
int a = 20;
int b =30;
printf("a=%d\n",a);
printf("b=%d\n",b);
printf("c=%d\n",c);
return 0;
}
複製代碼
輸出
a=20
b=30
c=40
複製代碼
type arrayName [ arraySize ];
複製代碼
這是一個一維數組,arraySize必須是大於0的常量,type是任意有效的c數據類型,聲明一個含有10個double數據的nums數組
double nums [10];
複製代碼
初始化固定數量的數組
int nums [3] = {10,2,3}
複製代碼
初始化數量不固定的數組
int nums []={1,2,3,4,5}
複製代碼
爲某個數組賦值
nums[3] = 6;
複製代碼
訪問數組元素
int a = num[3];
複製代碼
實例
#include <stdio.h>
int main(){
int n[10];
int i,j;
for(i=0;i<10;i++){
n[i]=i*10;
}
for (int j = 0; j < 10; ++j) {
printf("%d = %d\n",j,n[j]);
}
}
複製代碼
結果
0 = 0
1 = 10
2 = 20
3 = 30
4 = 40
5 = 50
6 = 60
7 = 70
8 = 80
9 = 90
複製代碼
枚舉是C語言中的一種基本數據類型
enum 枚舉名 {枚舉元素1,枚舉元素2,……};
複製代碼
假如咱們定義一週七天,假如不用枚舉,用常量
#define MON 1
#define TUE 2
#define WED 3
#define THU 4
#define FRI 5
#define SAT 6
#define SUN 7
複製代碼
假如用枚舉
enum Day{
MON=1, TUE, WED, THU, FRI, SAT, SUN
}
複製代碼
這樣看起來會很簡潔
注意:默認第一個成員變量爲0,後面的順序加1,若是第一個是1,後面是2,以此類推
1 先定義枚舉類型在定義變量
enum DAY{
MON=1, TUE, WED, THU, FRI, SAT, SUN
};
enum DAY day;
複製代碼
2 定義枚舉類型的同時定義枚舉變量
enum DAY
{
MON=1, TUE, WED, THU, FRI, SAT, SUN
} day;
複製代碼
3 省去枚舉名稱直接定義枚舉變量
enum
{
MON=1, TUE, WED, THU, FRI, SAT, SUN
} day;
複製代碼
實例
#include <stdio.h>
enum DAY {
MON = 1, TUE, WED, THU, FRI, SAT, SUN
};
int main() {
enum DAY day;
day=THU;
printf("enun= %d\n",day);
return 0;
}
複製代碼
結果
enun= 4
複製代碼
在C語言中,枚舉是被當作int
或者 unsigned int
來處理的,因此按照C語言規範是沒有辦法遍歷枚舉的
#include <stdio.h>
#include <stdlib.h>
enum Color {
red=1, green, blue
};
int main() {
enum Color enumColor;
printf("請選擇你喜歡的顏色(1 紅色 2 綠色 3 藍色)");
scanf("%d",&enumColor);
switch (enumColor){
case red:
printf("你喜歡紅色\n");
break;
case green:
printf("你喜歡綠色\n");
break;
case blue:
printf("你喜歡藍色\n");
break;
}
return 0;
}
複製代碼
結果
請選擇你喜歡的顏色(1 紅色 2 綠色 3 藍色)1
你喜歡紅色
複製代碼
每個變量都有一個內存位置,每個內存位置都定義了可以使用&符號
訪問地址,他表示在內存中的一個地址
#include <stdio.h>
int main(){
int a ;
int b[10];
printf("a 的內存地址=%p\n",&a);
printf("b 的內存地址=%p\n",&b);
return 0;
}
複製代碼
結果
a 的內存地址=0x7ffee5e086c8
b 的內存地址=0x7ffee5e086d0
複製代碼
指針是一個變量,其值爲另外一個變量的內存地址,使用指針以前須要對其進行聲明
type *var-name;
複製代碼
type
是指針的類型,他必須是一個有效的C數據類型,var-name
是指針的名稱,*
用來表示這個變量是指針。
int *aa;//一個整形指針
double *bb;//一個double類型的指針
複製代碼
使用指針會頻繁的進行以下幾個操做,定義一個指針變量,把變量地址賦值給指針,訪問指針變量中的可用地址
#include <stdio.h>
int main(){
int a =20;//定義int值
int *b;//定義指針
b=&a;//爲指針賦值
printf("變量的地址值=%p\n",&a);
printf("指針的值=%p\n",b);
printf("指針的地址值=%d\n",*b);
return 0;
}
複製代碼
結果
變量的地址值=0x7ffeef4356f8
指針的值=0x7ffeef4356f8
指針的地址值=20
複製代碼
變量聲明的時候,若是沒有明確的地址能夠賦值,爲指針賦值一個NULL是一個良好的習慣,賦值爲NULL被稱爲空指針
int main(){
int *var = NULL;
printf("var的地址爲=%p\n",var);
return 0;
}
複製代碼
var的地址爲=0x0
複製代碼
#include <stdio.h>
int main(){
int a;
int *b;
int **c;
a=40;
b=&a;
c=&b;
printf("a的值爲=%d\n",a);
printf("b的值爲=%d\n",*b);
printf("c的值爲=%d\n",**c);
return 0;
}
複製代碼
a的值爲=40
b的值爲=40
c的值爲=40
複製代碼
#include <stdio.h>
int sum(int *arr,int size);
int* getarr();
int main() {
int a[4] = {1, 2, 3, 4};
int v = sum(a,4);
printf("sum=%d\n",v);
int *p = getarr();
for (int i = 0; i < 4; ++i) {
printf("數組=%d\n",*(p+i));
printf("數組=%d\n",p[i]);
}
return 0;
}
int sum(int *arr, int size) {
int sum = 0;
for (int i = 0; i < size; ++i) {
printf("i=%d\n", arr[i]);
printf("i=%d\n", *(arr+i));
sum+=arr[i];
}
return sum;
}
int * getarr(){
static int arr[4]={2,4,5,7};
return arr;
}
複製代碼
i=1
i=1
i=2
i=2
i=3
i=3
i=4
i=4
sum=10
數組=2
數組=2
數組=4
數組=4
數組=5
數組=5
數組=7
數組=7
複製代碼
C指針用數字表示地址,所以能夠進行算術運算,++,--,+,-等,假如prt是一個int類型的地址1000,那麼執行prt++,prt將指向1004,即當前位置移動4個字節,假如prt是一個char類型的地址1000,那麼執行prt++,prt將指向1001,這個跟類型也是相關的
遞增一個指針
#include <stdio.h>
const int Max = 3;
int main() {
int arr[3] = {1, 2, 3};
int i ,*p;
//給p指針賦值數組中第一個元素的地址
p = arr;
for (int i = 0; i < Max; ++i) {
printf("元素的地址=%p\n", p);
printf("元素的地址=%d\n", *p);
//移動到下個位置
p++;
}
return 0;
}
複製代碼
元素的地址=0x7ffee165b6ac
元素的地址=1
元素的地址=0x7ffee165b6b0
元素的地址=2
元素的地址=0x7ffee165b6b4
元素的地址=3
複製代碼
有一種狀況,咱們數組內能夠存儲內存地址值
#include <stdio.h>
const int Max= 3;
int main(){
int arr[3]={1,2,3};
int *p[Max];
for (int i = 0; i <Max ; ++i) {
p[i]=&arr[i];
}
for (int j = 0; j < Max; ++j) {
printf("指針數組數據=%p\n",p[j]);
printf("指針數組數據值=%d\n",*p[j]);
}
return 0;
}
複製代碼
指針數組數據=0x7ffee7cda6ac
指針數組數據值=1
指針數組數據=0x7ffee7cda6b0
指針數組數據值=2
指針數組數據=0x7ffee7cda6b4
指針數組數據值=3
複製代碼
指針也能夠指向指針
#include <stdio.h>
int main(){
int a = 10;
int *b;
int **c;
b=&a;
c=&b;
printf("a的值爲=%d\n",a);
printf("b的值爲=%d\n",*b);
printf("c的值爲=%d\n",**c);
}
複製代碼
a的值爲=10
b的值爲=10
c的值爲=10
複製代碼
#include <stdio.h>
#include <time.h>
void getlong(unsigned long *a);
int main() {
unsigned long b;
getlong(&b);
printf("b的值爲=%ld\n",b);
}
void getlong(unsigned long *a) {
*a = time(NULL);
return;
}
複製代碼
b的值爲=1585048748
複製代碼
函數指針是指向函數的指針變量,函數指針能夠向普通函數同樣,傳遞參數,調用函數
函數返回值類型 (* 指針變量名) (函數參數列表);
複製代碼
#include <stdio.h>
int max(int, int);
int main() {
//p是函數指針
int (*p)(int, int) = &max;//&能夠省略
int a, b, c, d;
printf("請輸入三個數字:");
scanf("%d,%d,%d", &a, &b, &c);
d = p(p(a, b), c);//至關於調用max(max(a,b),c);
printf("d的值爲=%d\n", d);
return 0;
}
int max(int a, int b) {
return a > b ? a : b;
}
複製代碼
輸出
請輸入三個數字:1,2,3
d的值爲=3
複製代碼
#include <stdio.h>
#include <stdlib.h>
void setvalue(int *arr, int b, int(*p)(void)) {
for (int i = 0; i < b; ++i) {
arr[i] = p();
}
}
int stett(int(*p)(void)){
return p();
}
int getvalue(void) {
return rand();
}
int main() {
int arr[10];
setvalue(arr, 10, getvalue);
for (int i = 0; i < 10; ++i) {
printf("i=%d\n", arr[i]);
}
int b;
b= stett(getvalue);
printf("b=%d\n", b);
return 0;
}
複製代碼
結果
i=16807
i=282475249
i=1622650073
i=984943658
i=1144108930
i=470211272
i=101027544
i=1457850878
i=1458777923
i=2007237709
b=823564440
複製代碼
C語言定義字符串Hello,兩種形式,字符串和字符數組的區別:最後一位是不是空字符
#include <stdio.h>
int main(){
char hello[6]= {'H','e','l','l','o','\0'};
char hello1[]= "hello";
char *hello2="hello";
printf("測試=%s\n",hello);
printf("測試=%s\n",hello1);
printf("測試=%s\n",hello2);
return 0;
}
複製代碼
測試=Hello
測試=hello
測試=hello
複製代碼
結構體能夠存儲不一樣類型的數據項
定義一個結構體
struct tag {
member-list
member-list
member-list
...
} variable-list ;
複製代碼
struct Book {
int book_id ;
char title[50];
char author[50];
char subject[50];
} book;
複製代碼
在通常狀況下,tag、member-list、variable-list 這 3 部分至少要出現 2 個。如下爲實例:
//此聲明聲明瞭擁有3個成員的結構體,分別爲整型的a,字符型的b和雙精度的c
//同時又聲明告終構體變量s1
//這個結構體並無標明其標籤
struct {
int a;
char b;
double c;
} s1;
//此聲明聲明瞭擁有3個成員的結構體,分別爲整型的a,字符型的b和雙精度的c
//結構體的標籤被命名爲SIMPLE,沒有聲明變量
struct SIMPLE {
int a;
char b;
double c;
};
//用SIMPLE標籤的結構體,另外聲明瞭變量t一、t二、t3
struct SIMPLE t1, t2[20], *t3;
//也能夠用typedef建立新類型
typedef struct {
int a;
char b;
double c;
} Simple2;
//如今能夠用Simple2做爲類型聲明新的結構體變量
Simple2 u1, u2[20], *u3;
複製代碼
//結構體包含其餘結構體
struct AA{
int a;
struct Book b;
};
//結構體包含本身的指針
struct BB{
int b;
struct BB *nextbb };
複製代碼
struct Book {
int book_id ;
char title[50];
char author[50];
char subject[50];
} book= {1,"c語言","小明","bb"};
複製代碼
title : c語言
author: 小明
subject: bb
book_id: 1
複製代碼
訪問結構體的成員能夠用.
符號,好比上方的book.title;
int main(){
struct Book book1;
strcpy(book1.title,"學習書");
strcpy(book1.author,"小紅");
strcpy(book1.subject,"111");
book1.book_id=222;
printf("title : %s\nauthor: %s\nsubject: %s\nbook_id: %d\n", book1.title, book1.author, book1.subject, book1.book_id);
return 0;
}
複製代碼
title : 學習書
author: 小紅
subject: 111
book_id: 222
複製代碼
void printstuct(struct Book book);
int main(){
struct Book book1;
strcpy(book1.title,"學習書");
strcpy(book1.author,"小紅");
strcpy(book1.subject,"111");
book1.book_id=222;
printf("title : %s\nauthor: %s\nsubject: %s\nbook_id: %d\n", book1.title, book1.author, book1.subject, book1.book_id);
printstuct(book1);
return 0;
}
void printstuct(struct Book book){
printf( "Book title : %s\n", book.title);
printf( "Book author : %s\n", book.author);
printf( "Book subject : %s\n", book.subject);
printf( "Book book_id : %d\n", book.book_id);
}
複製代碼
title : 學習書
author: 小紅
subject: 111
book_id: 222
Book title : 學習書
Book author : 小紅
Book subject : 111
Book book_id : 222
複製代碼
定義,賦值,調用
struct Books *struct_pointer;
struct_pointer = &Book1;
struct_pointer->title;
複製代碼
int main() {
struct Book book1;
strcpy(book1.title, "學習書");
strcpy(book1.author, "小紅");
strcpy(book1.subject, "111");
book1.book_id = 222;
printstuct1(&book1);
return 0;
}
void printstuct1(struct Book *book) {
printf("Book title : %s\n", book->title);
printf("Book author : %s\n", book->author);
printf("Book subject : %s\n", book->subject);
printf("Book book_id : %d\n", book->book_id);
}
複製代碼
Book title : 學習書
Book author : 小紅
Book subject : 111
Book book_id : 222
複製代碼
共用體是一個特殊的數據類型,容許在相同的儲存位置,儲存不一樣的數據類型,能夠定義一個帶有多個成員的共用體,可是任什麼時候候只能一個成員帶值
用union
定義共用體,
union [union tag]
{
member definition;
member definition;
...
member definition;
} [one or more union variables];
複製代碼
union tag
是可選的,每一個member definition;
都是標準的變量定義,如int i char b等,在分號以前能夠定義一個或多個共用體變量是可選的
定義一個成員有int,float,char[]的共用體
#include <stdio.h>
#include <string.h>
union Data {
int a;
char b[100];
float c;
};
int main() {
union Data data;
printf("數據長度=%lu\n", sizeof(data));
data.a = 1;
data.c = 10.00;
strcpy(data.b, "測試數據");
printf("數據%d\n",data.a);
printf("數據%f\n",data.c);
printf("數據%s\n",data.b);
return 0;
}
複製代碼
數據長度=100
數據-393497114
數據-5278115000342806695772160.000000
數據測試數據
複製代碼
咱們看到數據a,c成員的值有損壞,是由於最後賦值的變量佔用了的內存位置,這也是b變量能夠正確輸出的緣由
咱們同一時間只能使用一個變量
#include <stdio.h>
#include <string.h>
union Data {
int a;
char b[100];
float c;
};
int main() {
union Data data;
printf("數據長度=%lu\n", sizeof(data));
data.a = 1;
printf("數據%d\n",data.a);
data.c = 10.00;
printf("數據%f\n",data.c);
strcpy(data.b, "測試數據");
printf("數據%s\n",data.b);
return 0;
}
複製代碼
數據長度=100
數據1
數據10.000000
數據測試數據
複製代碼
在這裏全部的成員均可以正確輸出,是由於同一時間只用到了一個變量
C語言提供typedef
關鍵字,可使用它爲類型起一個新的名字
#include <stdio.h>
typedef unsigned int TEXT;
int main(){
TEXT a = 11;
printf("參數爲=%d\n",a);
return 0;
}
複製代碼
參數爲=11
複製代碼
也能夠爲用戶自定義的數據類型去一個新的名字,好比結構體
#include <stdio.h>
#include <string.h>
typedef unsigned int TEXT;
typedef struct BOOKS {
char a[50];
char b[50];
} Book;
int main() {
TEXT a = 11;
printf("參數爲=%d\n", a);
Book book;
strcpy(book.a, "測試1");
strcpy(book.b, "測試2");
printf("a=%s\n", book.a);
printf("b=%s\n", book.b);
return 0;
}
複製代碼
參數爲=11
a=測試1
b=測試2
複製代碼
#define
是一個C指令,用於爲各類數據類型定義別名,與typedef
相似,可是他有如下幾種不一樣
typede
f僅限於爲類型定義符號名稱,#define
不只爲類型定義別名,也能夠爲數值定義別名typedef
爲編譯器解釋執行,#define
爲預編譯器進行處理#define TRUE 0
#define FALSE 1
int main() {
printf("數值爲=%d\n", TRUE);
printf("數值爲=%d\n", FALSE);
return 0;
}
複製代碼
數值爲=0
數值爲=1
複製代碼
int getchar(void)
函數從屏幕讀取下一個可用的字符,並把它返回爲一個整數。這個函數在同一個時間內只會讀取一個單一的字符。您能夠在循環內使用這個方法,以便從屏幕上讀取多個字符。
int putchar(int c)
函數把字符輸出到屏幕上,並返回相同的字符。這個函數在同一個時間內只會輸出一個單一的字符。您能夠在循環內使用這個方法,以便在屏幕上輸出多個字符。
#include <stdio.h>
int main(){
printf("請輸入一個字符\n");
int a = getchar();
printf("你的輸入爲\n");
putchar(a);
printf("\n");
}
複製代碼
請輸入一個字符
text
你的輸入爲
t
複製代碼
char *gets(char *s)
函數從stdin讀取一行到s指向的緩存區,直到一個終止符或一個EOF int puts(const char *s)
函數吧一個字符串s和一個尾隨的換行符寫入stdout
#include <stdio.h>
int main(){
char a[100];
printf("輸入你的字符\n");
gets(a);
printf("你輸入的字符爲\n");
puts(a);
return 0;
}
複製代碼
輸入你的字符
text
你輸入的字符爲
text
複製代碼
int scanf(const char *format, ...)
函數從標準輸入流 stdin 讀取輸入,並根據提供的 format 來瀏覽輸入。
int printf(const char *format, ...)
函數把輸出寫入到標準輸出流 stdout ,並根據提供的格式產生輸出。
format 是一個簡單的常量字符串,可是你能夠定義%s,%d,%c,%f來讀取字符串,數字,字符,浮點數
#include <stdio.h>
int main() {
char a[100];
int b;
printf("輸入文字\n");
scanf("%s%d", a, &b);
printf("你輸入的文字=%s,%d\n",a,b);
return 0;
}
複製代碼
輸入文字
text 123
你輸入的文字=text,123
複製代碼
#include <stdio.h>
int main() {
FILE *file;
//打開文件容許讀寫,若是不存在則建立該文件
file = fopen("/Users/renxiaohui/Desktop/test.txt", "w+");
//寫入一行
fprintf(file, "this is a text\n");
//再寫入一行
fputs("this is a text aaaa\n", file);
fclose(file);
}
複製代碼
會在建立文件test.txt,並寫入倆行文字
#include <stdio.h>
int main() {
FILE *file1;
char a[255];
//打開一個文件,只讀
file1 = fopen("/Users/renxiaohui/Desktop/test.txt", "r");
//讀取文件,當遇到第一個空格或者換行符會中止讀取
fscanf(file1, "%s", a);
printf("1= %s\n", a);
//讀取字符串到緩衝區,遇到換行符或文件的末尾 EOF返回
fgets(a, 255, file1);
printf("2= %s\n", a);
fgets(a, 255, file1);
printf("3= %s\n", a);
//關閉文件
fclose(file1);
}
複製代碼
讀取剛纔建立的文件
1= this
2= is a text
3= this is a text aaaa
複製代碼
C預處理器不是編譯器的組成部分,他是編譯過程當中的一個單獨步驟,他們會在編譯器實際編譯以前完成所需的預處理
全部的預處理器都是以(#)開頭的,他必須是第一個非空字符,爲了加強可讀性,預處理器應該從第一列開始,下面列出比較重要的預處理器
指令 | 描述 |
---|---|
#define | 定義宏 |
#undef | 取消定義的宏 |
#include | 包含一個源文件代碼 |
#ifdef | 若是宏已經定義則返回真 |
#ifndef | 若是宏沒有定義則返回真 |
#if | 若是給定條件爲真則編譯一下代碼 |
#else | #if的替代方案 |
#elseif | 若是前面的 #if 給定條件不爲真,當前條件爲真,則編譯下面代碼 |
#endif | 結束一個#if。。#else 語句 |
#error | 遇到標準錯誤是,輸出錯誤消息 |
#pragma | 使用標準化方法,向編譯器發佈特殊指令到編譯器中去 |
#define MAX 20
複製代碼
這個指令表示,把全部的MAX定義爲20,使用#define定義常量能夠增長可讀性
#include <stdio.h>
#include "myheader.h"
複製代碼
第一個表示從系統庫獲取stdio.h
庫,並添加到源文件中,一個是從本地目錄獲取myheader.h
,並添加到源文件中
#undef FILE
#define FILE 99
複製代碼
取消已經定義的FILE,並把它從新定義爲99
#ifdef MESSAGE
#define MESSAGE "you wish"
#endif
複製代碼
這個表示只有MESSAGE未定義時,才定義MESSAGE爲you wish
ANSI C中預約義宏,咱們能夠在編程中使用這些宏,但不能夠改變他的值
宏 | 描述 |
---|---|
1__DATE__ | 當前日期,一個以 "MMM DD YYYY" 格式表示的字符常量。 |
1__TIME__ | 當前時間,一個以 "HH:MM:SS" 格式表示的字符常量。 |
1__FILE__ | 這會包含當前文件名,一個字符串常量。 |
1__LINE__ | 這會包含當前行號,一個十進制常量。 |
1__STDC__ | 當編譯器以 ANSI 標準編譯時,則定義爲 1。 |
看下使用
#include <stdio.h>
int main() {
printf("data=%s\n",__DATE__);
printf("file=%s\n",__FILE__);
printf("time=%s\n",__TIME__);
printf("line=%d\n",__LINE__);
printf("stdic=%d\n",__STDC__);
return 0;
}
複製代碼
data=Mar 31 2020
file=text27.c
time=15:31:49
line=19
stdic=1
複製代碼
參數化宏能夠模擬函數,例以下面是一個計算數字平方的方法
int square(int x) {
return x * x;
}
複製代碼
能夠用參數化宏來表示
#define square(x) ((x)*(x))
複製代碼
在使用參數化宏以前必須使用#define來定義,參數列表必須包含在圓括號內的,而且必須緊跟在宏名稱以後,不容許有空格
#define square(x) ((x)*(x))
int main() {
printf("平方爲=%d\n",square(5));
return 0;
}
複製代碼
平方爲=25
複製代碼
宏延續運算符(\)
一個宏一般寫在一個單行上,可是若是宏太長,一個單行容不下,則使用宏延續運算符(\)例如
#define message_for(a,b) \ printf(#a"and "#b"we are friend\n")
複製代碼
字符串常量化運算符(#)
在宏定義中,須要把一個宏的參數轉化爲字符串常量時,則使用字符串常量化運算符(#)例如:
#define message_for(a,b) \ printf(#a"and "#b"we are friend\n")
int main() {
message_for("xiaoming","xiaohong");
return 0;
}
複製代碼
"xiaoming"and "xiaohong"we are friend
複製代碼
** 標記粘貼運算符(##)**
直接看代碼比較
#define add(n) printf("token" #n " = %d\n",token##n)
int main() {
int token34 =40;
add(34);
return 0;
}
複製代碼
token34 = 40
複製代碼
這個是怎麼發生的,由於這個實際會從編譯器中產出如下實際輸出
printf ("token34 = %d", token34);
複製代碼
defined()運算符
預處理器defined運算符是在常量表達式中的,用來肯定一個標識符是否已經#define定義過,若是定義過爲真,若是沒有定義過值爲假
#if !defined(TEXT)
#define TEXT "text\n"
#endif
int main() {
printf(TEXT);
return 0;
}
複製代碼
text
複製代碼