1.scanf函數
scanf("%d %d")//1 2
scanf("price%d %d") //price1 2
// 意思就是scanf函數中,格式是什么,就要對應的輸入什么,不然讀取不到輸入的變量
2.常量:const int AMOUNT = 100;
不能再次修改
const int AMOUNT = 100;
AMOUNT = 90 //會報錯,提示AMOUNT只讀
3.數據類型
//整數int
printf("%d",...)
scanf("%d",...)
//帶小數點的數double
printf("%f",...)
scanf("%lf",...)
4.十進制輸入,十六進制輸出
int x ;
scanf("%d",&x);
printf("%x",x);
5.使用 if或else后面要加{},因為else是和最近的if匹配。
//當a=7,b=6時,程序的輸出是:沒有結果。if ( a=6 )if ( b=7 )printf("A") ;
elseprintf ("B") :
6.如果在嵌套的for循環中,需要跳出最外層循環,可以使用連續傳遞break或goto,使用goto時,需要在跳出的位置寫 out:
#include <stdio.h>
int main(){int one,two,five;int x;int exit = 0;scanf("%d",&x);for(one = 1;one < x *10;one ++){for(two = 1;two < x *10;two ++){for(five = 1;five < x *10;five ++){if (one + two * 2 + five * 5 == x *10){printf("%d元需要%d個1角,%d個2角,%d個3角\n",x,one,two,five);//exit = 1;// break;goto out;}}//if (exit ) break;}//if (exit ) break;}
out:return 0;
}
7.sizeof( )
(1)是一個運算符,給出某個類型或變量在內存中所占據的字節數。
sizeof(int),sizeof(i)
(2)是靜態運算符,它的結果在編譯時刻就決定了
(3)不要在sizeof的括號里做運算,這些運算是不會做的。
8.unsigned
(1)如果一個字面量常數想要表達自己是unsigned,可以在后面加u或U。
(2)用l或L表示long(long)
(3)*unsigned的初衷并非擴展數能表達的范圍,而是為了做純二進制運算,主要是為了移位。
9.char
char是一種整數,也是一種特殊的類型:字符。
因為:(1)用單引號表示的字符字面量:‘a’,‘1’
(2)''也是一個字符
(3)printf和scanf里用%c來輸入輸出字符。
10.逗號運算符:
? 逗號用來連接兩個表達式,并以其右邊的表達式的值作為它的結果。逗號的優先級是所有運算符中最低的,所以它兩邊的表達式會先計算;逗號的組合關系是自左向右,所以左邊的表達式會先計算,而右邊的表達式的值就留下來作為逗號運算的結果。
? 一般只在for循環中使用。for(i=0,j=10;i<j;i++,j–)
11.求數組的大小:
int a[]{0};
sizeof(a)/sizeof(a[0]);//得到的是數組的個數。
12.輸出變量的地址:%p
int i = 0;
printf("%p\n",&i);
13.C語言printf格式化輸入輸出:
%c | 格式化輸出單個字符 |
---|---|
%p | 表示輸出這個指針 |
%d | 表示后面的輸出類型為有符號的10進制整型 |
%u | 表示無符號10進制整型 |
%lu | 表示輸出無符號長整型整數 (long unsigned) |
%i或%d | int |
%o | 八進制 |
%x | 十六進制 |
%X | 字母大寫的十六進制 |
%e或%E | 指數 |
%g或%G | float |
%n | 讀入/寫出的個數 |
%s | 字符串 |
%f或%F | float |
%a或%A | 十六進制浮點 |
%c | char |
14.運算符&:
獲得變量的地址,它的操作數必須是變量;
15.指針:就是保存地址的變量
int i;
int* p= &i;
int* p,q; //p是指針,q是普通的int型變量
int *p,q; //p是指針,q是普通的int型變量
int *p,*ql //p,q都是指針
16.*:是一個單目運算符,用來訪問指針的值所表示的地址上的變量。
17.指針是const
表示一旦得到了某個變量的地址,不能指向其他變量
int * const q = &i;//q是const,q不能指向其他地址
*q = 26; //OK
q ++ ;//ERROR
18.所指是const
表示不能通過這個指針去修改那個變量(并不能使得那個變量成為const)
const int *p = &i;
*p = 26; //ERROR!(*p)是const
i = 26; //OK
p = &j; //OK
總結:要么是指針不可以修改,要么是通過指針不能修改。
判斷哪個被const了的標志是const在 * 的前面還是后面。如果在前面:所指的東西不能被修改,如果在后面:指針不能被修改。
19.將一個非const的值轉換成const的
void f (const int* x);
int a = 15;
f(&a); // ok
const int b = a;
f(&b); //ok
b = a + 1;Error!
當要傳遞的參數的類型比地址大的時候,這是常用的手段:既能用比較少的字節數傳遞值給參數,又能避免函數對外面的變量的修改。
20.const數組
const int a[] = {1,2,3,4,5,6};
/*
數組變量已經是const的指針了,這里的const表明數組的每個單元都是 const int
所以必須通過初始化進行賦值
*/
22 *p++
- 取出p所指的那個數據來,完事之后順便把p移到下一個位置去
- *的優先級雖然高,但是沒有++高
- 常用于數組類的連續空間操作
- 在某些CPU上,這可以直接被翻譯成一條匯編指令
22.指針比較
- <.<=,==,>,>=,!= 都可以對指針做
- 比較它們在內存中的地址
- 數組中的單元的地址肯定是線性遞增的。
- 0地址
- 當然你的內存中有0地址,但是0地址通常是個不能隨便碰的地址
- 所以你的指針不應該具有0值
- 因此可以用0地址來表示特殊的事情:
- 返回的指針是無效的;
- 指針沒有被真正初始化(先初始化為0)
- NULL是一個預定定義的符合,表示0地址
- 有編譯器不愿意你用0來表示0地址
24.指針的類型
- 無論指向什么類型,所有的指針的大小都是一樣的,因為都是地址
- 但是指向不同類型的指針是不能直接互相賦值的
- 這是為了避免用錯指針。
25.指針的類型轉換
- void*表示不知道指向什么東西的指針
- 計算時與char*相同(但不相通)
- 指針也可以轉換類型
- int *p = &i; void *q = (void *)p;
- 這并沒有改變p所指的變量的類型,而是讓后人用不同的眼光通過p看它所指的變量。
- 當用q看時,不再是int啦,認為是個void!
26.用指針來做什么
- 需要傳入較大的數據時用作參數
- 傳入數組后對數組做操作
- 函數返回不止一個結果
- 需要用函數來修改不止一個變量
- 動態申請的內存
- 動態內存分配
#include <stdio.h>
#include <stdlib.h>
int main(void){int number;int* a;int i;printf("輸入數量:");scanf("%d",&number);a = (int*)malloc(number*sizeof(int));for(i=0;i<number;i++){scanf("%d",&a[i]);}//逆序輸出for(i=number-1;i>0;i--){printf("%d",a[i]);}//釋放內存free(a);return 0;
}
28.malloc, #include <stdlib.h>
void * malloc(size_t size);
- 向malloc申請的空間的大小是以字節為單位的
- 返回的結果是void*,需要類型轉換為自己需要的類型。
- (int*)malloc( n * sizeof(int))
29.free()
- 把申請得來的空間還給“系統”
- 申請過的空間,最終都應該要還
- 只能還申請來的空間的首地址
30.字符串
- 以0(整數0)結尾的一串字符
- 以0或’\0’是一樣的,但是和’0’不同,'0’代表ascall碼值48。
- 0標志字符串的結束,但它不是字符串的一部分
- 計算字符串長度的時候不包含這個0
- 字符串以數組的形式存在,以數組或指針的形式訪問
- 更多的是以指針的形式
- string.h里有很多處理字符串的函數
- C語言的字符串是以字符數組的形態存在的
- 不能用運算符對字符串做運算
- 通過數組的方式可以遍歷字符串
- 唯一特殊的地方是字符串字面量可以用來初始化字符數組
- 以及標準庫提供了一系列字符串函數
31.char*
- 字符串可以表達為char*的形式
- char*不一定是字符串
- 本意是指向字符的指針,可能指向的是字符的數組(就像int*一樣)
32.空字符串
- char buffer[100]=" ";
- 這是一個空的字符串,buffer[0]==‘\0’;
- char buffer[]=“”;
- 這個數組的長度只有1!
33.putchar
- int putchar(int c);
- 向標準輸出寫一個字符
- 返回寫了幾個字符,EOF(-1)表示寫失敗
33.getchar
-
int getchar(void);
-
從標準輸入讀入一個字符
-
返回類型是int,而不是char,是為了返回EOF(-1)
- Windows -> Ctrl + Z
- Unix -> Ctrl+D
34.string.h
-
strlen
- size_t strlen(const char *s);
- 返回s的字符串長度(不包括結尾的0)
-
strcmp
- int strcmp(const char *s1,const char *s2);
- 比較兩個字符串,返回
- 0:s1==s2
- 1:s1>s2
- -1:s1<s2
-
strcpy
- char * strcpy(char *restrict dst,const char *restrict src);
- 把src的字符串拷貝到dst
- restrict表明src和dst不重疊(C99)
- 返回dst
- 為了能鏈起代碼來
-
strcat
- char *strcat(char *restrict s1,const char * restrict s2);
- 把s2拷貝到s1的后面,接成一個長的字符串
- 返回s1
- s1必須具有足夠的空間
//安全版本,不會出現越界
char * strncpy(char *restrict dst,const char* restrict src,size_t m);
char * strncat(char *restrict s1,const char* restrict s2,size_t n);
int strncmp(const char*s1,const char * s2,size_t m);
35.復制一個字符串
- char *dst = (char *)malloc(strlen(src)+1);
- strcpy(dst,src);
36.枚舉
-
枚舉是一種用戶定義的數據類型,它用關鍵字 enum 以如下語法來聲明:
enum 枚舉類型名字{名字0,…,名字n };
-
枚舉類型名字通常并不真的使用,要用的是在大括號里的名字,因為它們就是常量符合,它們的類型是int,值則一次從0到n。如:enum colors{red,yellow,green};
-
就創建了三個常量,red 的值是0,yellow是1,而green是2。
-
當需要一些可以排列起來的常量值時,定義枚舉的意義就是給了這些常量的值的名字。
37.結構作為函數參數
- 整個結構可以作為參數的值傳入函數
- 這時候是在函數內新建一個結構變量,并復制調用者的結構的值。
- 也可以返回一個結構,這與數組完全不同。
38.自定義數據類型(typedef)
- C語言提供了一個叫 typedef 的功能來聲明一個已有的數據類型的新名字。如:
- type int Length; 使得 Length 成為 int 類型的別名。
- 這樣,Length 這個名字就可以代替int出現在變量定義和參數聲明的地方了:
- Length a,b,len;
- Length numbers[10];
39.全局變量
- 定義在函數外面的變量是全局變量
- 全局變量具有全局的生存期和作用域
- 它們與任何函數都無關
- 在任何函數內部都可以使用它們、
- 沒有做初始化的全局變量會得到0值
- 指針會得到NULL值
- 只能用編譯時刻已知的值來初始化全局變量
- 它們的初始化發送在main函數之前
- 如果函數內部存在與全局變量同名的變量,則全局變量會被隱藏40.
40.靜態本地變量
- 在本地變量定義時加上 static 修飾符就成為靜態本地變量
- 當函數離開的時候,靜態本地變量會繼續存在并保持其值
- 靜態本地變量的初始化只會在第一次進入這個函數時做,以后進入函數時會保持上次離開的值
- 靜態本地變量實際上是特殊的全局變量(地址放在一個區域)
- 它們位于相同的內存區域
- 靜態本地變量具有全局的生存期,函數內的局部作業域
- static在這里的意思是局部作用域(本地訪問)
41.返回指針的函數
- 返回本地變量的地址是危險的
- 返回全局變量或靜態本地變量的地址是安全的
- 返回在函數內malloc的內存是安全的,但是容易造成問題
- 最好的做法是返回傳入的指針
42.宏
# define 用來定義一個宏
-
如果一個宏的值中有其他宏的名字,也是會被替換的
-
如果一個宏的值超過一行,最后一行之前的行末需要加\
-
宏的值后面出現的注釋不會被當作宏的值的一部分
-
預定義的宏
__LINE__ //第幾行 __FILE__ //文件名 __DATE__ //日期 __TIME__ //時間 __STDC__ //判斷編譯器是否符合ANSIC標準,符合時為1,否則未定義
-
像函數的宏
#define cube (x) ((x)*(x)*(x))
- 帶參數的宏的原則
- 一切都要括號
- 可以帶多個參數,也可以組合(嵌套)使用其他宏
- 整個值都要括號
- 參數出現的每個地方都要括號
#define RADTODEG(x) ((x)*57.29578)#define NIN(a,b) ((a)>(b)?(b):(a))
43.頭文件
- 把函數原型放到一個頭文件(以.h結尾)中,在需要調用這個函數的源代碼文件(.文件)中引入# include 這個頭文件,就能讓編譯器在編譯的時候知道函數的原型。
- 在使用和定義這個函數的地方都應該#include這個頭文件
- 一般的做法就是任何.c都有對應的同名.h,把所有對外公開的函數的原型和全局變量的聲明都放進去
- 只有聲明可以被放在頭文件中
- 是規則不是法律
- 否則會造成一個項目中多個編譯單元里有重名的實體
- *某些編譯器允許幾個編譯單元中存在同名的函數,或者用weak修飾符來強調這種存在。
- 同一個編譯單元里,同名的結構不能被重復聲明
- 如果你的頭文件里有結構的聲明,很難做到這個頭文件不會在一個編譯單元里被#include多次
44.# include
- 是一個編譯預處理指令,和宏一樣,在編譯之前就處理了
- 它把那個文件的全部文本內容原封不動地插入到它所在的地方,所有也不是一定要在.c文件的最前面#include
45.不對外公開的函數
- 在函數前面加上static就使得它成為只能在所在的編譯單元中被使用的函數
- 在全局變量前面加上static就使得它成為只能在所在的編譯單元中被使用的全局變量
46.變量的聲明
- int i; 是變量的定義
- extern int i ; 是變量的聲明
47.聲明和定義
- 聲明是不產生代碼的東西
- 函數原型
- 變量聲明
- 結構聲明
- 宏聲明
- 枚舉聲明
- 類型聲明
- inline聲明
- 定義是產生代碼的東西
- 函數
- 全局變量
48.標準頭文件結構
- 運用條件編譯和宏,保證這個頭文件在一個編譯單元中只會被#include一次
#ifndef __LIST_HEAD__
#define __LIST_HEAD__#ednif
- 000”#pragma once 也能起到相同的作用,但是不是所有的編譯器都支持。
48.打開文件
#include <stdio.h>
int main(){FILE *fp = fopen("12.in","r");if(fp){int num;fscanf(fp,"%d",&num);printf("%d\n",num);fclose(fp);}else{printf("無法打開文件\n");}return 0;
}
49.二進制文件
- 其實所有的文件最終都是二進制的
- 文本文件無非是用最簡單的方式可以讀寫的文件
- more、tail、cat、vi
- 而二進制文件是需要專門的程序來讀寫的文件
- 文本文件的輸入輸出是格式化,可能經過轉碼
50.位段
- 可以直接用位段的成員名稱來訪問
- 比移位、與、或還方便
- 編譯器會安排其中的位的排列,不具有可移植性
- 當所需的位超過一個int時會采用多個int