一、經過預處理聲明常量java
#include <stdio.h> #define PRICE 100 int main() { printf("價格:%d\n",PRICE); return 0; }
二、經過 const 關鍵字聲明常量c++
#include <stdio.h> const int NUM=10; int main() { printf("數量:%d\n",NUM); return 0; }
區別:#define 在運行時會替換爲指定的值,const能夠看到數據類型,更推薦使用 const數組
在C語言中分爲有符號和無符號整型,無符號是整數,有符號包含負數函數
類型 | 說明 |
---|---|
short | 2字節 |
int | 4字節 |
long | 32位系統4字節,64位系統8字節 |
long long | 8字節 |
int main() { int a=10; int b=-10; long long c=20; int d=0b111;//二進制 int e=0xb;//十六進制 int f=010;//八進制 unsigned int g=12;//無符號正數 printf("a=%d,b=%d,c=%d,d=%d",a,b,c,d); return 0; }
進制相關知識參考其餘教程ui
c11 標準 stdint.h 對數據的長度進行了統一指針
類型 | 說明 |
---|---|
int8_t | 統一8位1字節 |
int16_t | 2字節 |
int32_t | 4字節 |
int64_t | 8字節 |
uint8_t | 無字符1字節 |
類型 | 說明 |
---|---|
float | 單精度,4字節,32位 |
double | 雙精度,8字節,64位 |
long double | 長雙精度,16字節,128位 |
typedef uint8_t mychar; int main() { mychar ch='a'; printf("%c",ch); return 0; }
自定義類型至關於對類型起了個別名code
使用 goto 實現循環orm
int i=0; aa: printf("%d\n",i); i=i+1; if(i<100){ goto aa; }
標籤名:
標記一個位置,goto 標籤名;
跳轉到指定標籤位置,標籤名能夠本身定義。blog
相關函數文檔參考:C語言stdio.h文檔教程
putchar:寫字符到標準輸出,至關於調用 putc
遍歷字符並打印
#include <stdio.h> int main() { char c; for (c='a';c<='z';c++) { putchar(c); putchar('\n'); } return 0; }
說明:char 類型佔用1字節,每一個字符都映射對應一個整數。
查看字符對應整數
#include <stdio.h> int main() { char c; printf("=====小寫====\n"); for (c='a';c<='z';c++) { printf("%d\n",c); } printf("=====大寫====\n"); for (c='A';c<='Z';c++) { printf("%d\n",c); } return 0; }
大寫字符和小寫字符恰好差距32,
putchar('A'+32);
可轉爲小寫。
puts:寫字符串到標準輸出
輸出字符串示例
#include <stdio.h> int main() { char string [] = "Hello world!"; puts(string); return 0; }
printf:打印格式化數據到標準輸出,若是包含格式說明符(以%開頭的子串)將格式化,用附加參數替換說明符(說明符能夠認爲是佔位符)。
格式化時用到的說明符
符號 | 解釋 | 舉例 |
---|---|---|
d 或者 i | 有符號十進制整數 | 392 |
u | 無符號十進制整數 | 7235 |
o | 無符號八進制 | 610 |
x | 無符號十六進制整數 | 7fa |
X | 無符號十六進制整數(大寫) | 7FA |
f | 十進制浮點,小寫 | 392.65 |
F | 十進制浮點,大寫 | 392.65 |
e | 科學記數法(尾數/指數),小寫 | 3.9265e+2 |
c | 字符 | a |
s | 字符串 | hello |
p | 指針地址(內存地址) | b8000000 |
% | %%打印出一個% | % |
格式化輸出示例
#include <stdio.h> int main() { printf("字符:%c %c\n",'a',65); printf("整數:%d %ld\n",600,6500000L);//%ld 長整 printf("浮點數:%f\n",33.3); printf("十六進制:%x\n",0xffa); printf("特殊打印:%%\n"); return 0; }
結果
字符:a A 整數:600 6500000 浮點數:33.300000 十六進制:ffa 特殊打印:%
getchar:從標準輸入中獲取字符
獲取字符示例
#include <stdio.h> int main() { uint8_t c; puts("輸入文本,在一個句子中包含.以結束:"); do{ c=getchar(); putchar(c); }while (c!='.'); return 0; }
uint8_t c;
uint8_t 大小與char同樣
gets:從標準輸入中獲取字符串
獲取字符串示例
#include <stdio.h> int main() { char str[256]; puts("輸入你的名字:"); gets(str); printf("你的名字:%s\n",str); return 0; }
scanf:從標準輸入中讀取格式化數據,格式化說明符可參照 printf
格式化輸入示例
#include <stdio.h> int main() { char ch; int num; char str[10]; puts("輸入一個字符:"); scanf("%c",&ch); printf("用戶的輸入字符爲:%c\n",ch); puts("輸入一個整數:"); scanf("%d",&num); printf("用戶輸入的整數爲:%d\n",num); puts("輸入字符串:"); scanf("%s",str); puts(str); return 0; }
int、char 等類型須要用&符號取得變量內存地址,變量 str 是一個數組,自己存儲的就是內存地址,因此不用加上&符號。(能夠理解爲值與引用)
建立數組方式1:
const int NUMS_LEN=10; int nums[NUMS_LEN];
數組中元素的內存地址沒有作過任何處理,有可能被以前其餘程序使用過,因此數組中的默認的值是不可預期的。
演示數組中元素默認值:
#include <stdio.h> int main() { const int NUMS_LEN=10; int nums[NUMS_LEN]; for (int i = 0; i < NUMS_LEN; ++i) { printf("索引:%d,值:%d\n",i,nums[i]); } return 0; }
建立數組方式2:
int ages[]={19,20,30};
建立方式1:
int nums[3][4]; for (int i = 0; i < 3; ++i) { for (int j = 0; j < 4; ++j) { printf("%d,%d,value=%d\n",i,j,nums[i][j]); } }
建立方式2:
int nums[2][3]={ {1,2,3}, {4,5,6} };
二維數組直接初始化值須要指定長度!
若是想對數組中的元素清0,能夠在遍歷中爲元素賦值爲0.
聲明字符串並檢查長度:
char str[10]; printf("長度:%ld\n",strlen(str));
strlen 函數用於檢測字符數組中字符的長度
存入字符串並檢查長度:
char str[10]="hello"; printf("長度:%ld\n",strlen(str));
\0做爲字符串結尾:
char str[10]="he\0llo"; printf("長度:%ld\n",strlen(str));
字符串中不論內容多少,只要遇到
\0
就認爲字符串結束!
char數組填充函數 memset:
memset(要填充的數組,要填充的值,要填充多長)
#include <stdio.h> #include <string.h> int main() { char str[]="你好"; memset(str,1,6); for (int i = 0; i < 6; ++i) { printf("%d\n",str[i]); } return 0; }
關於中文:
char str[2]="你好"; printf("長度:%ld\n",strlen(str));//一個漢字佔用3字節
strcat:鏈接字符串,將源字符串的副本附加到目標字符串。
#include <stdio.h> #include <string.h> int main() { char * str="hello";//要拼接的字符 char result[100];//目標字符 memset(result,0,100);//填充0到目標字符 strcat(result,str);//拼接str到result strcat(result,"world");//拼接 world 到result puts(result); return 0; }
strncat:鏈接指定數量的字符到目標字符串
#include <stdio.h> #include <string.h> int main() { char dist[10]; strncat(dist,"hello",3); puts(dist); return 0; }
結果
hel
sprintf:將格式化數據寫入字符串(格式方式和其餘格式化方法很像)
#include <stdio.h> #include <string.h> int main() { char str[10]; memset(str,0,10); int len,a=10,b=5; len=sprintf(str,"%d+%d=%d",a,b,a+b); printf("格式結果:[%s],長度爲:%d",str,len); return 0; }
結果:
格式結果:[10+5=15],長度爲:7
sscanf:從字符串中讀取格式化數據
使用 sscanf 截取數據
#include <stdio.h> #include <string.h> int main() { //原字符串 char sentence[]="Java is 23 years old"; //保存拆分出來的數據的變量 int age; char name[10]; sscanf(sentence,"%s %*s %d",name,&age); printf("age is %d,name is %s",age,name); return 0; }
"%s %*s %d"
分別表示了Java is 23
(空格也包含在內),%*s
表示匹配的字符串但忽略該數據(能夠理解佔了個位置)。&age
這裏須要將基本類型的內存地址引入。
使用 sscanf 轉換數據類型
#include <stdio.h> int main() { char * str="100"; int a; sscanf(str,"%d",&a); printf("轉換後:%d",a); return 0; }
使用 atof 將字符串轉爲 double
#include <stdio.h> #include <stdlib.h> int main() { double result=atof("3.14"); printf("轉換後:%f",result); return 0; }
==
用來比較兩個變量的內存地址,不能比較字符串的值。使用 strcmp 比較兩個字符串的值,兩個字符串的值相等返回 0。
#include <stdio.h> #include <string.h> int main() { char * str1="hello"; char str2[]="hello"; if(strcmp(str1,str2)==0){ puts("兩個字符串的值相等"); }else{ puts("兩個字符串的值不相等"); } return 0; }
strchr:從指定字符開始截取
#include <stdio.h> #include <string.h> int main() { char * str="helloworld"; char * result=strchr(str,'w'); puts(result); return 0; }
strrchr:從最後一個指定字符開始截取
#include <stdio.h> #include <string.h> int main() { char * str="helloworld"; char * result=strrchr(str,'l'); puts(result); return 0; }
strstr:從指定字符串開始截取
#include <stdio.h> #include <string.h> int main() { char * str="helloworld"; char * result=strstr(str,"wo"); puts(result); return 0; }
區分大小寫
strncpy:從字符串中複製指定長度字符
#include <stdio.h> #include <string.h> int main() { char * str="helloworld"; char dest[10]; strncpy(dest,str,5); puts(dest); return 0; }
使用指針從指定位置開始截取
#include <stdio.h> #include <string.h> int main() { char * str="helloworld"; char * str1=str+5; puts(str1); return 0; }
能夠先利用指針操做從某個位置開始截取,而後利用 strncpy 截取指定個。
聲明和調用的方式和java很類似
main 函數的參數,也是程序運行時的參數
聲明時需指定:1.參數的長度,2.參數數組
#include <stdio.h> int main(int argc,char ** argv) { printf("參數的個數:%d\n",argc); for (int i = 0; i < argc; ++i) { printf("參數 %d 的值:%s\n",i,argv[i]); } return 0; }
#include <stdio.h> #include <stdarg.h> void testarg(int n,...){ printf("參數的個數:%d\n",n); va_list args; va_start(args,n); for (int i = 0; i < n; ++i) { int temp=va_arg(args,int); printf("參數:%d\n",temp); } va_end(args); } int main(int argc,char ** argv) { testarg(2,10,55); return 0; }
函數設置可變參數時需指定參數個數形參
int n
,和...
(任意個數的參數)。需引入頭文件 stdarg.h,va_list
類型保存有關變量參數的信息,va_start
初始化變量參數列表,va_arg
取出參數的值,va_end
結束使用變量參數列表
除了能夠用 #define 定義一個常量,還能夠在編譯參數中指定預設常量的值
編寫沒有聲明常量但使用了常量的代碼
#include <stdio.h> int main() { printf("The num is %d\n",THE_NUM); return 0; }
使用命令進行編譯和運行
gcc -o test main.c -DTHE_NUM=4 test.exe
-o
參數指定編譯後可執行文件的文件名,-D
參數後面直接跟常量名和值(沒有空格)
1.編寫代碼
#include <stdio.h> #define WIN 1 #define LINUX 2 #define MAC 3 int main() { #if PLATFORM==WIN printf("Hello Windows\n"); #elif PLATFORM==LINUX printf("Hello Linux\n"); #elif PLATFORM==MAC printf("Hello MAC\n"); #else printf("Unknow platform\n"); #endif return 0; }
if、#elif、#else、#endif 這些都是編譯條件,用於決定代碼塊是否編譯
2.編譯時指定條件
//編譯源碼 gcc -o test main.c -DPLATFORM=1 //運行 test.exe
1.建立a.h
#include "b.h"
2.建立b.h
#include "a.h"
3.引入a.h
#include <stdio.h> #include "a.h" int main() { return 0; }
修改a.h
#ifndef A_H #define A_H #include "b.h" #endif
修改b.h
#ifndef B_H #define B_H #include "a.h" #endif
經過標記一個常量來判斷是否重複引入,一旦擁有這個常量將再也不引入
聲明一個變量後,系統會爲這個變量分配內存空間,每一個變量都有一個內存地址,至關於旅館的房間號。
咱們要獲取變量中的值須要經過內存地址來找到對應的值,可是還有另外一種狀況是這個變量中存放的是另個一變量的內存地址。這就好像你經過房間號找到這個房間,發如今這個房間裏面是另外一個房間的房間號。
因此,一個變量的地址就成爲該變量的指針。
聲明指針並指向一個變量的地址
#include <stdio.h> int main() { int *a,*b; int i=10; a=&i; b=&i; printf("a的值爲:%d\n",*a); printf("b的值爲:%d\n",*b); i=99; printf("a的值爲:%d\n",*a); printf("b的值爲:%d\n",*b); return 0; }
C語言用*表示指針,爲指針賦值時
&
取出變量的地址。(指針a和指針b指向同一個地址,修改i後指針中的也會改變,這個很相似Java和C#中的引用類型)
指針的大小
#include <stdio.h> int main() { int *a; printf("size is %ld\n", sizeof(a)); return 0; }
64位系統中爲8字節,32位中爲4字節
有參無返回值的函數指針
#include <stdio.h> void hello(int a,char* c){ printf("hello\n"); } int main() { void(*fp)(int,char*)=&hello; fp(1,""); return 0; }
有參有返回值的函數指針
#include <stdio.h> int test(int a){ printf("hello:%d\n",a); return a; } int main() { int(*fp1)(int)=&test; int result=fp1(11); printf("返回值:%d\n",result); return 0; }
給函數指針設定類型別名
#include <stdio.h> void hello(){ printf("Hello\n"); } typedef void(*SimpleHello)(); int main() { SimpleHello h1=&hello; h1(); SimpleHello h2=&hello; h2(); return 0; }
重複定義時能夠簡化代碼
無類型指針能夠表明全部類型的數據
無類型指針存放字符串
#include <stdio.h> int main() { void *test="Hello"; printf("%s\n",test); return 0; }
主要用結構體描述屬性
定義使用結構體
#include <stdio.h> struct File{ char* name; int size; }; int main() { struct File file; file.name="a.txt"; file.size=10; printf("文件 %s 的大小爲 %d\n",file.name,file.size); struct File file1={"a.jpg",100}; printf("文件 %s 的大小爲 %d\n",file1.name,file1.size); return 0; }
結構體也能夠像數組那樣初始化(C#中也有結構,二者比較像能夠對比記憶)
定義結構體類型簡化代碼
#include <stdio.h> typedef struct _File{ char* name; int size; }File; int main() { File file; file.name="a.txt"; file.size=10; printf("文件 %s 的大小爲 %d\n",file.name,file.size); File file1={"a.jpg",100}; printf("文件 %s 的大小爲 %d\n",file1.name,file1.size); return 0; }
結構體所佔大小如何計算的?結構的大小由各變量與字節最大變量對齊後相加得出。
如圖所示,三種狀況:
1.當定義第一個變量大小爲1字節,第二個變量比第一個變量大時,第一個變量要對齊大的變量,第一個變量填充爲2字節,結構體大小爲4字節。
2.前兩變量加起來不足對齊第三個變量的大小,因此填充2字節對齊,結構體大小爲8字節。
3.前4個變量加起來恰好對齊第5個變量的大小,無須對齊。最後一個變量沒有對齊則填充2個字節對齊第5個變量,因此結構體大小爲12字節。
#include <stdio.h> typedef struct _Data{ uint8_t a;//1 uint8_t b;//1 uint8_t c;//1 uint8_t d;//1 uint32_t e;//4 uint8_t f;//1 }Data; int main() { printf("size is %d\n", sizeof(Data)); return 0; }
此時結果爲12
沒有使用指針前
#include <stdio.h> typedef struct _Dog{ char * color; int age; }Dog; int main() { Dog dog1={"紅色",2}; Dog dog2=dog1; dog1.age=3; printf("(dog1 color is %s,age is %d),(dog2 color is %s,age is %d)\n" ,dog1.color,dog1.age,dog2.color,dog2.age ); return 0; }
沒有使用以前將dog1賦值給dog2至關於複製一個副本
使用結構體指針
#include <stdio.h> typedef struct _Dog { char *color; int age; } Dog; int main() { Dog dog1 = {"紅色", 2}; Dog *dog2 = &dog1; dog1.age = 3; printf("(dog1 color is %s,age is %d),(dog2 color is %s,age is %d)\n", dog1.color, dog1.age, dog2->color, dog2->age); return 0; }
指針操做用法和以前同樣,須要注意的地方是:結構體指針,獲取結構體的值時須要使用
->
,不然將編譯錯誤
經過函數建立和銷燬結構體指針
#include <stdio.h> #include <stdlib.h> typedef struct _Dog { char *color; int age; } Dog; Dog* createDog(char* color,int age){ Dog* dog=malloc(sizeof(Dog)); dog->color=color; dog->age=age; return dog; } void deleteDog(Dog* dog){ free(dog); } int main() { Dog* dog1=createDog("紅色",3); printf("(dog1 color is %s,age is %d)\n", dog1->color, dog1->age); deleteDog(dog1); return 0; }
malloc函數分配內存,使用完畢後用free函數釋放內存(釋放後的內存的值不可預期什麼時候修改,free函數調用後別的程序就可使用這塊空間了)
共同體的特色:共同體中聲明的全部變量共用一塊空間
聲明及使用共同體
#include <stdio.h> typedef union _BaseData{ char ch; uint8_t ch_num; }BaseData; int main() { BaseData data; data.ch='A'; printf("ch_num is %d size is %d\n",data.ch_num, sizeof(BaseData)); return 0; }
變量 ch_num 和 ch 共用同一內存地址,大小爲 1,共同體作類型轉換比較方便。
實現顏色的操做
#include <stdio.h> //定義顏色結構體 typedef struct _ColorARGB{ uint8_t blue; uint8_t green; uint8_t red; uint8_t alpha; }ColorARGB; //定義顏色共同體 typedef union _Color{ uint32_t color; ColorARGB colorARGB; }Color; int main() { Color c; c.color=0xFFAADD00; printf("red:%X",c.colorARGB.red); return 0; }
存入的數據是以小端模式,因此定義顏色結構體時的通道的順序和賦值的顏色順序相反。結合結構體與共同體實現(巧妙)
fopen函數:以指定文件名和模式獲取一個流的FILE指針。
支持的模式
模式 | 說明 |
---|---|
"r" | 讀:文件必須存在 |
"w" | 寫:建立一個文件,若是已經存在則覆蓋 |
"a" | 追加:向文件末尾追加內容,若是文件不存在則建立該文件 |
"r+" | 可作讀取和修改的操做,文件必須存在 |
寫文件
//建立文件指針 FILE * file=fopen("a.txt","w"); if (file){ //寫入內容 fputs("HelloWorld",file); //關閉 fclose(file); }else{ puts("文件操做失敗!"); }
讀文件
#include <stdio.h> int main() { FILE * file=fopen("a.txt","r"); if (file){ char ch; while(1){ ch=fgetc(file); if(ch!=EOF){ printf("%c\n",ch); }else{ break; } } fclose(file); } return 0; }