一、數據類型
1、基本數據類型
整形
short(signed、unsigned)
示例:
short a;
short int a;
int(signed、unsigned)
示例:
int a;
long(signed、unsigned)
示例:
short a;
long int a;
浮點型
float
示例:
float a;
double(long)
示例:
long double a;
字符
char(signed、unsigned)
示例:
char a;
字符串(字符指針char*/字符數組char []/字符常量)
示例:
char* a=NULL;(指針最好初始化)
char a[];
"abcdef"(字符常量)
2、聚合數據類型
數組
一維數組(a[2])
數組名是一個指向第一個元素地址的指針常量
定義:在一段地址連續的內存空間儲存相同數據類型的集合
訪問元素:下標訪問[],a[1]訪問a中索引為1的元素
示例:
int a[2] = {1,2};//初始化一個整形數組
多維數組
數組名是指向第一行向量地址的指針常量
定義:int a[][];
下標運算:最右邊[]里先變化
可以看出特殊的一維數組,只是數組中的元素也是數組,例如二維數組可以看成一維數組,其中元素也是一個一維數組
int a[2][2] = {{1,2},{3,4}};//在內存中是按照1,2,3,4存儲的
指針數組(其中元素是指針)
char* a[];//將char*看成int一樣的數據類型,只是數組元素不是int型而是字符指針類型
指針
int* a;int i; int b[];
定義:存儲地址的變量
初始化:需要用&給指針賦值, a = &i;a=b;
間接訪問(*): 訪問存儲地址上的對象
指針與數組:
*與[]:*(a+1)==a[1]==b[1];
++: a++ a的地址加一
邏輯運算:指向同一數組的指針可以比較大小(任何指針都可以比較相等不相等)
混淆點:誰在最后就是誰,指針數組就是數組,元素是指針。int* 看做一個整體,相當於int,都是數據類型
指針數組:int * p[];數組元素類型是指針
數組指針:int (*p)[];指向數組的指針
指針函數(返回類型是指針的函數):int* f();返回指向整形的指針,f是一個函數
函數指針(指向函數的指針):int (*f)(); f是指向函數的指針 該函數返回整形
指針與地址:指針存放地址
NULL指針:不指向任何地址的指針
注意:.(成員運算符)、->、()、[]優先級最高
結構體(struct)
定義:不同類型數據的集合
struct a {成員表列} 變量表列;
a是標簽
成員表列:類型說明符 成員名;
此時編譯器不會給a分配內存空間,只有聲明變量才會給變量分配地址
3種定義結構體類型變量的方法
1、先聲明結構體類型再定義變量名
struct stu{};
struct stu stu1;
2、聲明結構體類型的同時定義變量
struct stu{}stu1;
3、直接定義結構體變量
struct {} stu1;
初始化:struct a a1={x=1,x=2};
結構數組:元素類型是結構的數組
struct a a2[];
結構指針:指向結構類型的指針
struct a * a3;
結構成員訪問:
a1.x;
a3->x;(*a3).x
結構體自引用:
struct SELF_REF2{
int a;
struct SELF_REF2 *b;
int c;
};
結構體變量的引用
結構體變量不能整體輸入輸出,要使用結構體成員運算符訪問成員
printf("%s%c%d",stu1);
stu1.name;
可以整體賦值
stu2 = stu1;
只能對最低級成員進行賦值及運算
stu1.birth.moth;
可以引用結構體變量以及其成員的地址
結構指針變量做函數參數
1、結構體變量成員
2、結構體變量
3、結構體指針
聯合(union)
定義:同一地址內存上不同時刻存放不同數據
union a {成員表列} 變量表列;
a:標簽
成員表列:int a; float b;
變量表列:
a1,a2
初始化:
union {
int a;
float b;
char a[4];
} x={5};
成員訪問:x.a;
枚舉(enum)
定義
enum 枚舉名{枚舉元素1,枚舉元素2,...};
enum DAY
{
MON=1, TUE, WED, THU, FRI, SAT, SUN
};
注意:第一個枚舉成員的默認值為整型的 0,后續枚舉成員的值在前一個成員上加 1。我們在這個實例中把第一個枚舉成員的值定義為 1,第二個就為 2,以此類推。
可以在定義枚舉類型時改變枚舉元素的值:
enum season {spring, summer=3, autumn, winter};
沒有指定值的枚舉元素,其值為前一元素加 1。也就說 spring 的值為 0,summer 的值為 3,autumn 的值為 4,winter 的值為 5
枚舉變量的定義
前面我們只是聲明了枚舉類型,接下來我們看看如何定義枚舉變量。
我們可以通過以下三種方式來定義枚舉變量
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
enum DAY
{
MON=1, TUE, WED, THU, FRI, SAT, SUN
};
int main()
{
enum DAY day;
day = WED;
printf("%d",day);
return 0;
}
結果
3
在C 語言中,枚舉類型是被當做 int 或者 unsigned int 類型來處理的,所以按照 C 語言規范是沒有辦法遍歷枚舉類型的。
不過在一些特殊的情況下,枚舉類型必須連續是可以實現有條件的遍歷。
以下實例使用 for 來遍歷枚舉的元素:
#include
enum DAY
{
MON=1, TUE, WED, THU, FRI, SAT, SUN
} day;
int main()
{
// 遍歷枚舉元素
for (day = MON; day <= SUN; day++) {
printf("枚舉元素:%d \n", day);
}
}
結果
枚舉元素:1
枚舉元素:2
枚舉元素:3
枚舉元素:4
枚舉元素:5
枚舉元素:6
枚舉元素:7
以下枚舉類型不連續,這種枚舉無法遍歷。
enum
{
ENUM_0,
ENUM_10 = 10,
ENUM_11
};
枚舉在 switch 中的使用:
#include
#include
int main()
{
enum color { red=1, green, blue };
enum color favorite_color;
/* 用戶輸入數字來選擇顏色 */
printf("請輸入你喜歡的顏色: (1. red, 2. green, 3. blue): ");
scanf("%u", &favorite_color);
/* 輸出結果 */
switch (favorite_color)
{
case red:
printf("你喜歡的顏色是紅色");
break;
case green:
printf("你喜歡的顏色是綠色");
break;
case blue:
printf("你喜歡的顏色是藍色");
break;
default:
printf("你沒有選擇你喜歡的顏色");
}
return 0;
}
結果
請輸入你喜歡的顏色: (1. red, 2. green, 3. blue): 1
你喜歡的顏色是紅色
將整數轉換為枚舉
以下實例將整數轉換為枚舉:
#include
#include
int main()
{
enum day
{
saturday,
sunday,
monday,
tuesday,
wednesday,
thursday,
friday
} workday;
int a = 1;
enum day weekend;
weekend = ( enum day ) a; //類型轉換
//weekend = a; //錯誤
printf("weekend:%d",weekend);
return 0;
}
結果
weekend:1
二、控制流
1、順序
語句程序塊
例:
int i=1;
int a[3];
2、條件
if-else
switch
3、循環
while
do{}while
for()
三、函數
1、聲明 函數原型
void printd();
2、定義
返回值類型 函數名 (參數列表)
{
函數體
}
3、遞歸
直接間接調用自己,要有停止條件
四、動態存儲分配
數組的長度是預定義好的,在整個程序中固定不變。C語言不允許動態數組類型
1、常用的內存管理函數有以下三個
分配內存空間函數 malloc、calloc
釋放內存空間函數 free
2、malloc
函數原型:void* malloc(unsigned int size);
其作用是在內存的動態存儲區中分配一個長度為size的連續空間(size是一個無符號數),此函數的返回值是一個指向分配域起始地址的指針(void)
若此函數未能成功地執行(內存不足),返回空指針(NULL);
int * p = (int*)malloc(200*sizeof(int));
3、calloc
函數原型
void* calloc(unsigned n,unsigned size);
其作用是在內存的動態存儲區中分配n個長度為size的連續空間(size是一個無符號數),此函數的返回值是一個指向分配域起始地址的指針(void)
若此函數未能成功地執行(內存不足),返回空指針(NULL);用calloc函數可以為一維數組開辟存儲空間,n是數組元素個數,每個元素長度為size;
int * p = (int*)malloc(200,sizeof(int));
4、free
函數原型
void free(void* p);
其作用是釋放由p指向的內存區,使這個部分內存區能被其他變量使用。p是最近一次調用calloc或malloc函數時返回的值。
free(p);
五、頭文件
訪問方式
#include <頭文件>
1、輸入輸出:
定義輸入輸出函數、類型以及宏的數目占整個標准庫的三分之一
流:是與磁盤或其他外圍設備關聯的數據的源或目的的。文本流、二進制流
打開一個流就是將把該流與一個文件或設備連接起來,關閉流將斷開這種連接。
1.1文件操作
FILE *fopen(const char* filename, const char *mode);
fopen打開filename指定的文件,並返回一個與之相關聯的流。若打開失敗返回NULL。
mode:
"r":打開文本文件用於讀
"w":創建文本文件用於寫,並刪除已存在的內容
"a":追加;打開或創建文本文件,並向文件末尾追加內容
"r+":打開文本文件用於更新(讀和寫)
"w+":創建文本文件用於更新,並刪除已存在的內容
"a+":追加;打開或創建文本文件用於更新,寫文件時追加到文件末尾
在上述訪問模式之后加入b,如"rb"或"w+b"等,則表示對二進制文件進行操作。
FILE *freopen(const char* filename, const char *mode,FILE *stream);
freopen以mode打開filename指定的文件,並將該文件關聯到stream指定的流。返回stream;若打開失敗返回NULL。freopen函數一般用於改變與stdin、stdout、stderr相關聯的文件。
int fflush(FILE *stream);
對輸出流來說,fflush將已寫到緩沖區但尚未寫入文件的所有數據寫到文件中。對輸入流來說,其結果未定義。發生錯誤,返回EOF,否則返回0。
fflush(NULL)將清洗所有的輸出流。
int fclose(FILE *stream);
將所有未寫入的數據寫入stream中,丟棄緩沖區中的所有未讀輸入數據,並釋放自動分配的全部緩沖區,最后關閉流。若出錯則返回EOF,否則返回0。
int remove(const char *filename);
刪除filename指定的文件。失敗返回非0值。
int rename(const char* oldname, const char *newname);
修改文件的名字。失敗返回非0值。
FILE *tmpfile(void);
以模式"wb+"創建一個臨時文件,該文件在被關閉或程序正常結束時將被自動刪除。若創建成功,返回一個流,失敗返回NULL。
1.2格式化輸出
printf函數提供格式化輸出轉換。
int fprintf(FILE *stream, const char *format,...);
按照format說明的格式對輸出進行轉換,並寫到stream流中。返回值是實際寫入的字符數。若出錯返回一個負值。
格式串由普通字符(將被復制到輸出流中)與轉換說明(分別決定下一后續參數的轉換和打印,以%開頭,以轉換字符結束[%d])
在%與轉換字符之間可以依次包括下列內容:
標志,用於修改轉換說明
-:指定被轉換的參數在其字段內左對齊
+:指定在輸出的數前面加上正負號
空格:如果第一個字符不是正負號,則在其前面加上一個空格
0:對於數值轉換,當輸出長度小於字段寬度時,添加前導0進行填充
#:指定另一種輸出形式。如果為o轉換,則第一個數字為零;如果為x或X轉換,則指定在輸出值的非0值前加0x或0X;對於e、E、f、g或G轉換,指定輸出總包括一個小數點; 對於g或者G轉換,指定輸出值尾部無意義的0將被保留。
一個數值,用於指定最小字段寬度。
點號,用於分割字段寬度和精度
表示精度的數。
int printf(const char *format,...);
printf(...)等價於fprintf(stdout,...)
int sprintf(char * s, const char *format,...);
sprintf函數與printf函數基本相同,但其輸出將被寫入字符串s中,並以‘\0’結尾。
1.3格式化輸入
int fscanf(FILE *stream, const char* format,...);
根據格式串format從流stream中讀取輸入,並把轉換后的值賦值給后續各個參數,其中每個參數必須為指針。
int scanf(const char* format,...);
scanf(...)等價於fscanf(stdin,...)
int sscanf(const char *s,const char *format);
sscanf(s,...)函數與scanf(...)等價,不同的是,前者的輸入字符來源於字符串s
1.4字符輸入輸出函數
int fgetc(FILE *stream);
返回stream中下一個字符。若到達文件末尾或發生錯誤,則返回EOF
char *fgets(char *s, int n, FILE *stream);
最多將下n-1個字符讀入數組s中。若到達文件末尾或發生錯誤,則返回NULL。
int fputc(int c, FILE *stream);
把字符c(轉換為unsigned char類型)輸出到stream。返回寫入的字符,若發生錯誤,則返回EOF
int fputs(const char *s, FILE *stream);
字符串s(不含'\n')輸出到stream。返回非負值,若發生錯誤,則返回EOF。
int getc(FILE *stream);
等價於fgetc,不同的是,當getc函數定義為宏時,他可能多次計算stream的值。
int getchar(void);
等價於getc(stdin)
char* gets(char *s);
把下一個輸入行讀入數組s中,並把末尾的換行符替換成字符'\0',返回字符串s,若到達文件末尾或發生錯誤,則返回NULL。
int putc(int c,FILE *stream);
等價於fputc,不同的是,當putc函數定義為宏時,他可能多次計算stream的值。
int putchar(int c);
putchar(c)==putc(c,stdout);
int puts(const char *s);
把字符串s和一個換行符輸出到stdout中。發生錯誤返回EOF,否則返回非負值。
int ungetc(int c, FILE *stream)
把c寫回到流stream中,下次對該流進行讀操作時,將返回該字符。
1.5直接輸入輸出函數
size_t fread(void *ptr, size_t size, size_t nobj, FILE *stream);
從流stream中讀取最多nobj個長度為size的對象,並保存到ptr指向的數組中。返回讀取的對象數。
size_t fwrite(const void *ptr, size_t size, size_t nobj, FILE *stream);
從ptr指向的數組中讀取nobj個長度為size的對象,並輸出到流stream中。
1.6文件定位函數
int fseek(FILE *stream, long offset, int origin);
設置流stream的文件位置,后續的讀寫操作將從新位置開始。
long ftell(FILE *stream);
返回stream流的當前文件位置。
2、字符類別測試:
C 標准庫的 ctype.h 頭文件提供了一些函數,可用於測試和映射字符。
這些函數接受 int 作為參數,它的值必須是 EOF 或表示為一個無符號字符。
如果參數 c 滿足描述的條件,則這些函數返回非零(true)。如果參數 c 不滿足描述的條件,則這些函數返回零。
1 | int isalnum(int c) 該函數檢查所傳的字符是否是字母和數字。 |
2 | int isalpha(int c) 該函數檢查所傳的字符是否是字母。 |
3 | int iscntrl(int c) 該函數檢查所傳的字符是否是控制字符。 |
4 | int isdigit(int c) 該函數檢查所傳的字符是否是十進制數字。 |
5 | int isgraph(int c) 該函數檢查所傳的字符是否有圖形表示法。 |
6 | int islower(int c) 該函數檢查所傳的字符是否是小寫字母。 |
7 | int isprint(int c) 該函數檢查所傳的字符是否是可打印的。 |
8 | int ispunct(int c) 該函數檢查所傳的字符是否是標點符號字符。 |
9 | int isspace(int c) 該函數檢查所傳的字符是否是空白字符。 |
10 | int isupper(int c) 該函數檢查所傳的字符是否是大寫字母。 |
11 | int isxdigit(int c) 該函數檢查所傳的字符是否是十六進制數字。 |
標准庫還包含了兩個轉換函數,它們接受並返回一個 "int"
1 | int tolower(int c) 該函數把大寫字母轉換為小寫字母。 |
2 | int toupper(int c) 該函數把小寫字母轉換為大寫字母。 |
3、字符串函數<string.h>
string .h 頭文件定義了一個變量類型、一個宏和各種操作字符數組的函數。
定義了兩組字符串函數,一組函數的名字以str開頭,一組以mem開頭
NULL
這個宏是一個空指針常量的值。
size_t
這是無符號整數類型,它是 sizeof 關鍵字的結果
4、數學函數:<math.h>
math.h 頭文件定義了各種數學函數和一個宏。在這個庫中所有可用的功能都帶有一個 double 類型的參數,且都返回 double 類型的結果。
5、實用函數:<stdlib.h>
stdlib .h 頭文件定義了四個變量類型、一些宏和各種通用工具函數。
執行數值轉換、內存分配以及其他類似工作的函數。
6、日期與時間函數:<time.h>
time.h 頭文件定義了四個變量類型、兩個宏和各種操作日期和時間的函數
庫變量
1 | size_t 是無符號整數類型,它是 sizeof 關鍵字的結果。 |
2 | clock_t 這是一個適合存儲處理器時間的類型。 |
3 | time_t is 這是一個適合存儲日歷時間類型。 |
4 | struct tm 這是一個用來保存時間和日期的結構。 |
tm 結構的定義如下:
struct tm {
int tm_sec; /* 秒,范圍從 0 到 59 */
int tm_min; /* 分,范圍從 0 到 59 */
int tm_hour; /* 小時,范圍從 0 到 23 */
int tm_mday; /* 一月中的第幾天,范圍從 1 到 31 */
int tm_mon; /* 月,范圍從 0 到 11 */
int tm_year; /* 自 1900 年起的年數 */
int tm_wday; /* 一周中的第幾天,范圍從 0 到 6 */
int tm_yday; /* 一年中的第幾天,范圍從 0 到 365 */
int tm_isdst; /* 夏令時 */
};
庫函數
1 | char *asctime(const struct tm *timeptr) 返回一個指向字符串的指針,它代表了結構 timeptr 的日期和時間。 |
2 | clock_t clock(void) 返回程序執行起(一般為程序的開頭),處理器時鍾所使用的時間。 |
3 | char *ctime(const time_t *timer) 返回一個表示當地時間的字符串,當地時間是基於參數 timer。 |
4 | double difftime(time_t time1, time_t time2) 返回 time1 和 time2 之間相差的秒數 (time1-time2)。 |
5 | struct tm *gmtime(const time_t *timer) timer 的值被分解為 tm 結構,並用協調世界時(UTC)也被稱為格林尼治標准時間(GMT)表示。 |
6 | struct tm *localtime(const time_t *timer) timer 的值被分解為 tm 結構,並用本地時區表示。 |
7 | time_t mktime(struct tm *timeptr) 把 timeptr 所指向的結構轉換為一個依據本地時區的 time_t 值。 |
8 | size_t strftime(char *str, size_t maxsize, const char *format, const struct tm *timeptr) 根據 format 中定義的格式化規則,格式化結構 timeptr 表示的時間,並把它存儲在 str 中。 |
9 | time_t time(time_t *timer) 計算當前日歷時間,並把它編碼成 time_t 格式。 |