第二部分C語言重難點(diǎn)部分的理解
一.指針
-
指針定義的理解
#include<stdio.h> int main(void){ //定義一個(gè)char類型的指針,和int類型的變量 char * pc; int num =4; //此時(shí)的含義是pc指向了num的首地址 夯膀; //指針的類型決定了取值的時(shí)候訪問多少內(nèi)存 // 0000 0001 0000 0001 // char * 獲取數(shù)據(jù), 0000 0001 // short * 獲取數(shù)據(jù), 0000 0001 0000 0001 pc = # // 指針可以參與運(yùn)算,但是僅限于+和- // p+1表示指針向后移動類型單位長度 return 0; }
-
指針的用處
-
用函數(shù)實(shí)現(xiàn)兩個(gè)變量值的交換诗充,注意只是交換了地址也并不能交換值,必須交換兩個(gè)地址下的值才可實(shí)現(xiàn):
//只交換兩個(gè)變量的地址,也不能實(shí)現(xiàn)交換 void swap2(int *px,int *py){ int *ptemp; ptemp = px; px = py; py = ptemp; } //通過指針改變了兩個(gè)值的內(nèi)容,實(shí)現(xiàn)了交換 void swap3(int *px,int *py){ //px -->a py---->b int ptemp; ptemp = *px; // ptemp = 3; *px = *py; // a = b; a = 5,b = 5 *py = ptemp; // b = 3; b = 3; }
通過指針能夠讓函數(shù)有多個(gè)返回值----所謂的多個(gè)返回值并不是多個(gè)return,而是一次性的修改多個(gè)變量的值
-
/實(shí)現(xiàn)計(jì)算器
void calculator(int x,int y,int *psum,int *pjian,int *pcheng,float *pchu){
//把x+y的結(jié)果放到主調(diào)函數(shù)中 sum變量中
*psum = x+y;
*pjian = x-y;
*pcheng = x*y;
*pchu = x/(float)y;
}
-
二級指針---其實(shí)二級指針就是指向指針的指針
//定義一個(gè)變量 int a = 0; //定義一個(gè)一級指針指向a,假設(shè)a的地址為0xf2 int *p = &a; p == 0xf2; *p == *0xf2 == a; //定義一個(gè)二級指針指向p int* *p1 = &p; //此時(shí)p1的內(nèi)存單元中存放的是p的地址,假設(shè)p的地址為0xf0 p1 == 0xf0; *p1 == *0xf0這個(gè)地址所指向的內(nèi)容 == 0xf2 **p1 == **0xf0 == *0xf2 == a;
-
數(shù)組指針
-
指向數(shù)組元素的指針
指針pa進(jìn)行+1或-1操作時(shí)不是內(nèi)存地址的加減,而是指向下一個(gè)數(shù)組元素或上一個(gè)
-
同一個(gè)數(shù)組中的兩個(gè)指針相減表示的是這兩個(gè)指針之間差多少個(gè)元素
//定義一個(gè)數(shù)組 int a[] = {1,2,3,4,5}; //定義一個(gè)指針指向數(shù)組a int *ap = a; //利用該指針遍歷數(shù)組a for (int i = 0; i < 5; i++){ printf("a[%d] = %d\n",i,*(ap+i)); }
-
指針變量之間的運(yùn)算
- 表示兩個(gè)指針之間相隔了幾個(gè)元素 诱建,真實(shí)地地址差:(p1-p) * sizeof(int) //12
-
-
函數(shù)指針與指針函數(shù)的區(qū)別
函數(shù)指針是返回值是指針的函數(shù)蝴蜓; 如:char * getDay(int n){……}
-
指針函數(shù)是指向函數(shù)的指針;
//格式:被指向的函數(shù)的返回值類型 (*函數(shù)指針變量名)(被指的函數(shù)的參數(shù)); //定義了一個(gè)函數(shù)指針,指針變量名是pmax,它只能指向返回值是int 并且有兩個(gè)int類型參數(shù)的函數(shù) int (*pmax)(int x,int y); // 形參的名可以省略 int (*pmax2)(int ,int );
二.程序的編譯及運(yùn)行
- C 語言程序從編寫源代碼到運(yùn)行經(jīng)歷哪些階段?
- 編寫源文件(源代碼)就是新建一個(gè)文本文件,然后編寫C語言源代碼int main() {...}
- 編譯(cc -c 文件名)利用命令cc -c 源文件名.c編譯源文件,然后生成目標(biāo)文件"原文件名.o"該編譯過程需要檢查語法等內(nèi)容,該文件是二進(jìn)制格式文件但是不能執(zhí)行
- 鏈接(cc 目標(biāo)文件) 將目標(biāo)文件與庫函數(shù)等鏈接到一起,使得程序可以執(zhí)行使用命令:cc 目標(biāo)文件名.o會默認(rèn)生成 a.out(assembly output(來源于Unix), 表示二進(jìn)制(binary)輸出文件)cc 1.c
- 注意事項(xiàng):
注意:在編寫程序,編譯的時(shí)候,如果檢查語法有錯(cuò)誤,就會報(bào)錯(cuò),阻止編譯繼續(xù)進(jìn)行但是函數(shù)比較特殊,如果函數(shù)調(diào)用,但是沒有提供函數(shù)的定義,那么會隱式的提供函數(shù)聲明.但是鏈接的時(shí)候,如果沒有提供函數(shù)體,那么就會報(bào)錯(cuò),阻止的鏈接的進(jìn)行,進(jìn)而不會生成可執(zhí)行文件茎匠;
三.宏的概念及無參宏定義方法
- 宏的定義: 宏: 預(yù)處理指令格仲,所有的以"#" 都是預(yù)處理指令,宏是一個(gè)特殊標(biāo)識符汽抚,代表一個(gè)字符串抓狭、數(shù)字伯病、表達(dá)式
- 宏的分類:
- 有參數(shù)的宏
- 無參數(shù)的宏
- 定義方式
- 無參數(shù)的宏的定義方式
- 格式: #define 宏名 宏所代表的內(nèi)容
- 注意:
- 不需要使用分號結(jié)束造烁,宏是一個(gè)預(yù)處理指令,不是語句
- 宏的名稱一般是大寫午笛,以便區(qū)別普通變量
- 宏惭蟋,一般我們寫在文件的開頭部分
- 有參數(shù)的宏的定義方式
- 格式:#define 宏名(形參) 宏代表的字符串
- 無參數(shù)的宏的定義方式
#define M(y) y*y+3*y
#define SUM(a,b) a+b
2. 使用注意事項(xiàng)
1. 有參宏的參數(shù)不會被分配內(nèi)存空間,不需要指定類型
2. 有參宏展開的時(shí)候:
1. 把實(shí)參帶入到宏的字符串中
2. 在出現(xiàn)宏名的地方用宏代表的字符串取替換
- 使用方式
- 宏可以參與運(yùn)算可以成為表達(dá)式的一部分
- 使用的注意事項(xiàng):
- 宏的替換 在程序編譯之前药磺,預(yù)處理程序 會把源代碼中所有出現(xiàn)宏名的地方就用用宏代表的內(nèi)容去替換告组,例外:當(dāng)宏名出現(xiàn)在字符串中,此時(shí)不會替換
- 宏定義的時(shí)候癌佩,可以嵌套
- 在程序中出現(xiàn)宏名的地方木缝,僅僅使用宏代表的值做替換
- 注意事項(xiàng)
-
typedef和#define的區(qū)別
//定義一個(gè)宏 #define INT2 int * //這是給 int* 起個(gè)別名 INT typedef int * INT; int main(int argc, const char * argv[]) { int num = 2; //使用宏定義指針變量 INT2 p,p5; // int *p,p5; //p是一個(gè)指針變量 //p5 就是一個(gè)整形變量 //用typedef(定義)方式,定義指針變量 INT p1,p6; //INT 原型 int * //int *p1,*p6; //p1 是指針變量 //p6也是指針變量 return 0; }
-
四.代碼的練習(xí)
- 推箱子的小游戲
#define kRows 10
#define kCols 11
#include<stdio.h>
//定義一個(gè)函數(shù)實(shí)現(xiàn)地圖的繪制
void drawMap(char map[kRows][kCols]) {
for(int i = 0; i < kRows; i++){
printf("%s\n",map[i]);
}
}
//定義一個(gè)函數(shù)實(shí)現(xiàn)移動围辙,當(dāng)前位置元素和下一個(gè)位置的元素互換
void movel(char map[kRows][kCols],int oldX,int oldY,int newX,int newY){
char temp;
temp=map[oldX][oldY];
map[oldX][oldY]=map[newX][newY];
map[newX][newY]=temp;
}
int main(int argc ,const char * argv[]){
//1.定義二維數(shù)組,用來保存地圖
char map[kRows][kCols]={
"##########",
"#O #### #",
"# X#### #",
"# #",
"###### #",
"# #### #",
"# #",
"# ######",
"# ",
"##########"};
//2.繪制地圖
drawMap(map);
//3.提示游戲的玩法
printf("請控制小人移動:w.上 s.下 a.左 d.右 q.推出\n");
//4.定義一些變量我碟,保存位置信息,保存玩家輸入的方向
char direction; //保存玩家輸入的方向
// 保存用戶當(dāng)前的位置
int personX = 1;
int personY = 1;
//初始化小人得下一個(gè)位置
int nextX = personX;
int nextY = personY;
char street = ' ';
char box = 'X';
//保存箱子的當(dāng)前位置
int boxX=2;
int boxY=2;
//5.編寫循環(huán)控制程序
while(1){
//1)接受玩家輸入的方向 a\n d\n
scanf("%c",&direction);
getchar();
//防止穿墻
nextX=personX;
nextY=personY;
//2)根據(jù)玩家輸入的方向姚建,判斷將要移動的方向
switch(direction){
case 'w':
case 'W':
//記錄小人的下一個(gè)位置
nextX--;
break;
case 's':
case 'S':
//記錄小人的下一個(gè)位置
nextX++;
break;
case 'a':
case 'A':
//記錄小人的下一個(gè)位置
nextY--;
break;
case 'd':
case 'D':
//記錄小人的下一個(gè)位置
nextY++;
break;
case 'q':
case 'Q':
printf("程序正在退出...\n");
printf("程序已經(jīng)退出...\n");
return 0;
default:
break;
}
// 3)判斷小人的將要移動的位置是否是路
if(map[nextX][nextY]==street){
//如果是路矫俺,讓小人移動
movel(map,personX,personY,nextX,nextY);
//重新保存小人的最新位置
personX=nextX;
personY=nextY;
} else if(map[nextX][nextY]==box){
// 再判斷小人的下一個(gè)位置是否是箱子
// 如果是箱子:
// 1) 計(jì)算箱子的下一個(gè)位置
int boxNextX = boxX+(boxX-personX);
int boxNextY = boxY+(boxY-personY);
// 2) 再判斷 箱子的下一個(gè)位置是否是路
if (map[boxNextX][boxNextY] == street) {
// 如果是路:
// 1)箱子和箱子下一個(gè)位置交換
movel(map, boxX, boxY, boxNextX, boxNextY);
// 2)小人和箱子的位置進(jìn)行交換
movel(map, personX, personY, boxX, boxY);
// 3)重新保存小人的位置,箱子的位置
boxX = boxNextX;
boxY = boxNextY;
personX = nextX;
personY = nextY;
}
}
drawMap(map);
if(boxY==9){
printf("哇哦啊,你推出來掸冤!");
break;
}
}
}