NTNUCIC
台師大資訊研究社
對資訊相關有興趣的人都來~~
林品儒
www.github.com/aigecko
師大貓耳控
喜歡Asm,Ruby和Crystal
在C/C++中深奧難懂的神祕名詞
代表記憶體的位置
可以取出變數的記憶體位置
或是從指定位置取出值
雖然各種型別佔用空間可能不一樣
但是他們的指標都是一樣大的
可能是32或64位元視編譯器和系統而定
變數名稱前面加上星號*
這樣"該變數"就會是該型別的指標
對變數使用&當前綴的話可以取得其指標
對指標使用*前綴則可以取得該位址放的值
注意地址和放的東西不一定一樣
指標的值為0(NULL)則為空指標
不可以對空指標取值不然會發生錯誤
指標初始化時儘量初始化為空指標
不是不爆 時候未到
地址和放的值不會一樣
指標可以指派給變數
#include <stdio.h>
int main(){
int a=0x5566;
int *p=&a;
printf("%X %X %X %X %X",a,p,*p,&a,*(&a));
}
取得指標後可以對該位置的值進行存取
可以讀也可以寫入
#include <stdio.h>
int main(){
int n=4850;
int *p=&a;
*p=7850
printf("%X %X %X %X %X",a,p,*p,&a,*(&a));
}
既然可以使用指標存取值
那就可以將兩個變數的值交換
提示:宣告變數a,b並宣告指標p,q指派a,b的位址
要使用陣列需要使用指標進行操作
宣告陣列要在變數名稱後加上使用[]
陣列宣告時要指定大小
可以用{}將其元素初始化
可以手動指定大小
也可以把元素指派好後自動知道大小
#include <stdio.h>
int main(){
bool arr[4],table[]={true,false,false};
char list[5]={'a','b','c','d','e'};
printf("%d %d %d",
sizeof(arr)/sizeof(bool),
sizeof(table)/sizeof(bool),
sizeof(list)/sizeof(char));
return 0;
}
字串其實是一種char陣列
但是字串最後的元素是NULL字元
把字串裝進變數可使用陣列宣告方式
char str[]="hello, world"
陣列中的放的東西稱為元素
要取出元素必須要索引代表其位置
索引值從0開始
使用[]來取得指定索引的元素
觀察字串索引以及元素的變化
觀察初始化但未指定的陣列
觀察未初始化的陣列
#include <stdio.h>
int main(){
char str[]="abcdef";
int arr[4]={22,66};
short uninit[2];
printf("%d %d %d\n",str[0],str[5],str[6]);
printf("%d %d %d\n",arr[0],arr[1],arr[2]);
printf("%hd %hd",uninit[0],uninit[1]);
}
陣列的頭可以代表該型態的指標
對於指標可以進行加減法來移動
移動的矩離和該型別的大小相關
加法減法可以使用
還可以使用 ++ 遞增
以及使用 -- 遞減
注意!此兩個運算子是地雷請小心使用
可以用來迭代整個陣列
記得陣列本身可以轉成該型別指標
#include <stdio.h>
int main(){
int arr[]={100,200,0};
int *p=arr; //注意這裡直接把arr給p
printf("%d ",*p);p++;
printf("%d ",*p);p++;
printf("%d ",*p);p++;
}
使用指標取出指定索引的值
#include <stdio.h>
int main(){
int arr[]={478,771,775};
int *p=arr;
printf("%d %d\n",*(arr+0),arr[0]);
printf("%d %d\n",*(arr+1),arr[1]);
printf("%d %d\n",*(arr+2),arr[2]);
}
其實中括號就是幫我們精減語法
陣列也可以裝指標
使用printf列印陣列中的字串
const char *arr[3]={
"coppermine",
"thunghbird",
"northwood"
};
使用const關鍵字前綴代表常數
常數不可以被更改
但是有指標時就要小心了
#include <stdio.h>
int main(){
int a=4004;
const int *p; //指向的值不能改
int * const q=&a; //指標本身不能改
const int * const r=&a; //都不能改
}
看看const在 * 的哪一邊
放前面就是常數的指標
放後面就是指標的常數
兩個都有就是常數的指標常數
補上p和q的宣告讓輸出為8008 8008
#include <stdio.h>
int main(){
int a=8087,b=8008;
//宣告不同型態的p和q
p=&b;
*q=*p;
printf("%d %d",*p,a);
}
為什麼輸出很早就講了而沒有講輸入
因為輸入要有指標才能做到
scanf可傳入格式以及多個指標
將輸入的值以指定格式取代指標指的值
其他的格式相同,只有以下不同
"%f"對應單精度浮點數
"%d"對應雙精度浮點數
"%s"對應字串(記得字串空間要夠大)
要知道佔用的記憶體有多大才能放好放滿
語法參考 scanf("%d",&n);
宣告以下型態的變數並在輸入後輸出其值
unsigned int,long long int,float及double
在講解分支指令前需要先知道比較運算
對兩個運算元比較之後得出其真假值
大於 > 大於等於 >=
小於 < 小於等於 <=
相等 == 不相等 !=
要注意的是相等的等號有2個而非1個
由於字串其實是指標
不同字串在記憶體中的位置不會一樣
因此直接比較指標沒有意義
要比較兩方指標所指的值有無相同
#include <string.h>
其中有strcmp可以傳入兩個字串
字串相等時回傳0
前字串小於後字串回傳負值
前字串大於後字串回傳正值
列印以下字串的比較結果
"i7-6700","i5-6500"
"p4 631","p4 631"
"MX440","R4850"
使用條件讓程式執行流程改變
所以才需要講解比較運算
不同語言的分支指令語法可能略有出入
最簡單的分支指令
if(條件){想執行的內容}
此處的右大括號後方是不需要分號的
用在只有某種情況才要執行的時候
#include <stdio.h>
int main(){
if(3==8){
printf("impossible!!");
}
}
二分法的分支指令
if(條件){想執行的內容}
else{否則執行這裡}
條件符合就往if去,不合則往else去
用在不同狀況有不同處理
#include <stdio.h>
int main(){
if('Z'>'B'){
printf("Just do it!");
}
else{
printf("Don't do that.");
}
}
多個條件的判斷
if(條件){想執行的內容}
else if(條件){某些內容}
else{不然就執行這裡}
#include <stdio.h>
int main(){
unsigned int n;scanf("%ud",&n);
if(n<50){printf("You get nothing.");}
else if(n<80){printf("You get dirt.");}
else if(n<95){printf("You get stone.");}
else if(n<100){printf("You get gold");}
else{printf("Out of range");}
}
上面講的都是不同的判斷是來做分支
使用switch-case可以只對某變數的值做比較
因為語法很難描述就直接看實例吧
#include <stdio.h>
int main(){
char c;scanf(" %c",&c);
switch(c){
case '1':{
printf("Taiwan No.1");
break;
}
case '2':
case '3':
printf("2 or 3");
break;
case '4':
break;
default:
printf("other");
}
}
依照隨機的骰子列印不同的字串
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
int main(){
srand(time(NULL));
int dice=rand()%64;
//骰出0~7輸出"AL"
//骰出8~15輸出"AX"
//骰出16~31輸出"EAX"
//骰出32~63輸出"RAX"
//其他狀況輸出"QQ"
}
改變程式執行流程的除了分支還有迴圈
可以在特定狀況下重複執行程式碼
有各種不同功能的指令
最簡單的迴圈
while(條件){重複部份}
當條件符合時會執行大括號內的指令
執行完會再判斷是否符合條件
會一直執行而不會停止
剛好當成while語法的實例
#include <stdio.h>
int main(){
while(true){
printf(".");
}
}
可以使用ctrl+c停止程式
取得輸入整數取log2的整數部份
提示:使用除法將輸入的數每次除以2
提示:記得宣告另外的變數來遞增
進階版的迴圈但是更常用
for(初始化;條件;內容結束時執行){內容}
可以在初始化的地方宣告變數
在條件的部份撰寫所需條件
在內容結束時執行的部份遞增變數
要注意是2個分號而非逗號
for常常拿來做指定次數的迴圈
#include <stdio.h>
int main(){
for(int i=0;i<5;i++){
printf("now i is %d\n",i);
}
}
輸入數字指定迴圈的執行次數
輸入字串使讓迴圈執行時可以列印
使用for迴圈操作陣列的每個元素
#include <stdio.h>
int main(){
int arr[5];
for(int i=0;i<sizeof(arr)/sizeof(int);i++){
printf("arr[%d] is %d\n",i,arr[i]);
}
}
宣告有8個元素的整數陣列
把陣列中的每個元素變成其索引的平方數
此運算子可以補足分支指令的不足
可以同時判斷多個條件
使用 && 或and將兩個值取AND
要注意這裡是兩個&
是對兩個值進行操作而非其中的位元
兩個值為true才為true
否則為false
使用 || 或or將兩個值取OR
一樣要注意是2個|
兩個值任一為true就為true
其他就是false
可以用 ^ 或xor將兩個值取XOR
兩值相同則為false
兩值不同則為true
其實NOT應該歸類於邏輯運算子
可以用 ! 或not讓結果反向
false變成true
true變成false
這次是台師大資訊研究社第一次舉辦寒訓
當然採用直播也是第一次嘗試
希望可以讓大家對寫程式有初步的認識
此次寒訓課程就到此結束
感謝各位的收看及指教