[cs50x] week1 - C | hello world, mario, cash/credit
CS50 C大學生活暫時告一段落,最近終於騰出時間跟精力來認真讀這堂觀望許久的harvard神課CS50。今天這篇主要會是我自己看完David的上課影片+Brian詳細講解作業的影片+寫完所有作業並交出去確定正確之後的筆記,供我自己之後回來複習,如果可以幫到也要修課的同學就更好了!
code: https://github.com/yunchipang/cs50x
basics
David在開始動手寫code之前先定義了好的程式碼應該是correctness, good design, good style 缺一不可。
- correctness → your program runs correctly
- design → how well your code is written (do not repeat yourself!)
- style → readable & elegant
最基本的C起手式,先示範了印出hello, world
。
#include <stdio.h>
int main(void)
{
printf("hello, world");
}
老實說我從來沒有想過要學C,畢竟商院出身的就算走資料分析,也比較多用用Python, R, SQL而已,對我來說C就是一個遙遠的、困難的、艱澀的、與我無關的程式語言。但David第二堂課就教C,下定決心要好好讀完cs50的我只好硬著頭皮開始寫。之前聽實習好夥伴W說C是古老而嚴謹的語言,自己稍稍摸過一次之後終於懂了這種感覺!講直接一點,python有時候隨便寫寫都跑得起來,C卻是所有變數定義跟前置作業缺ㄧ不可。
problem set部分,我不知道我code這樣寫是不是最正確或是最快的方法,但他跑得動而且submit50
系統完全接受,所以先幫自己的心得跟產出做個紀錄,有空再來檢查跟優化,也歡迎批評指教!
pset1/hello
第一份作業(也是最簡單的暖身題)要求大家首先請user填入自己的名字name
,然後程式會return "hello, name"
給user。
#include <stdio.h>
#include <cs50.h>
int main(void)
{
// prompt the user for their name
string name = get_string("What is your name?\n");
// print out hello
printf("hello, %s\n", name);
}
pset1/mario
這份「印金字塔」的作業我卡了幾小時才解出來。當時自己覺得能力有限,所以先做了”less comfortable”的版本,不過觀念通了之後解”more comfortable”也就幾分鐘的事情(痛哭流涕)。
雖然之前寫python也有多多少少用過巢狀迴圈,但這種print出指定形狀的練習我從來沒做過,因此一開始多多少少有點困惑,但摸索之中好像有漸漸抓到訣竅。因為本身屬於圖像理解派(?),我自己的方法是畫出二維方格子,x軸的變數用i
, y軸用j
,幫所有方格子都編上(i, j)
這樣的號碼之後,會比較好想像印出指定形狀的#
的時候邏輯要怎麼寫。
1. less comfortable
印出向左傾斜的金字塔後,要印出向右傾斜的金字塔最重要的就是if (i + j < n - 1)
這行,因為用正方形來看的話,左下到右上的對角線以左都需印出空白,這區的條件就是i + j < n - 1
(不懂的話可以畫出來加加看!)
for (int i = 0; i < n; i++)
{
for (int j = 0; j < n; j++)
{
if (i + j < n - 1)
{
printf(" ");
}
else
{
printf("#");
}
}
printf("\n");
}
2. more comfortable
跟上ㄧ題是舉一反三的用法,一步一步由左到右寫出來。
- 向右傾斜金字塔金字塔(同上題)
- 中間margin=2的空白
- 向左傾斜金字塔(最簡單!)
pset1/cash
cash
這個作業是練習寫簡單的greedy algorithm(貪婪演算法),方法是把手上有的零錢做成一個array:money
,拿要找零的數字: cents
迴圈減掉比他自己小的最大的零錢money[i]
,每做一次就coins++
,最後得到coins
的數量。
// define the coins available
int money[4];
money[0] = 25;
money[1] = 10;
money[2] = 5;
money[3] = 1;
// counting coins
int coins = 0;
for (int i = 0; i < 4; i++)
{
while (cents >= money[i])
{
cents -= money[i];
coins++;
}
}
pset1/credit
credit無疑是week1最難的作業(畢竟是最後一份more comfortable),我大概斷斷續續解了三天才解出來,最後發現出錯的地方還是基本數學跟資料型態問題,在這裡記錄一下免得自己再犯一樣的錯。
1. modulo
上網查資料時發現有範例是用 % 9
來取得乘以二之後兩位數單獨相加的值(例如6
,6*2=12
,取1+2=3
),但credit.c
第一次成功complie再使用check50
檢查時卻發現放進去跑的credit card numbers輸出的output卻有對有錯!回頭print出number
, length
跟sum
進一步檢查,發現問題應該出在數字9。因為9*2=18
,1+8=9
,但是如果用 % 9
處理的話程式會return 0(天啊就是這種初丁數學問題)。所以正確的解法應該如下,把兩位數分開處理。
sum += ((two_n / 10) + (two_n % 10));
2. int vs char
第二個我犯的錯是把判讀這串數字是AMEX
, MASTERCARD
還是VISA
的跟開頭數字有關的條件都寫錯資料型態了。例如VISA卡號都是4開頭,我就寫str[0] == 4
然後complie之後所有卡號都return INVALID
,後來才發現問題就出在str
字串的一個字元str[0]
是char,所以要寫成str[0] == '4'
才對。
【課後心得】
耶依終於寫完C了!希望今年上半年可以努力堅持把CS50讀完,不可以放棄。不知道自己真心喜歡什麼的話,直接動手寫就會知道了。啊這裡再額外感謝一下父親總是可以一眼看出我bug在哪裡,雖然他取笑我的變數名稱取很爛,哼(好啦我會加油)