看板 Gossiping作者 jserv (松鼠)標題 Re: [問卦] C程式大神們請進時間 Sun Aug 27 23:46:44 2017
※ 引述《gash55025502 (白影弓)》之銘言:
: 聽說八卦版們各方面的神人們都很多
: 想必一定也有精通C語言的人
原來八卦板可以拿來討論 C 語言程式設計,太好了。
: 就是阿
支持文言文,這裡幫你改為「嗟夫」
: 輸入一個字串要將他做大小寫轉換
: 轉換是轉換成功了
: 但是後面卻跑出一堆亂碼
: 可以請大神們幫我看看問題出在哪嗎
為了避免變成暑修作業 (?),我提供一份實作,讓你想想,歡迎討論。
檔名: X.c
===從這裡開始===
#include <stdio.h>
#include <stdlib.h>
#include <ctype.h>
/* Reference:
*
http://www.geeksforgeeks.org/ \
* case-conversion-lower-upper-vice-versa-string-using-bitwise-operators-cc/
*/
static const int ascii_x = 32;
/* Lower to Upper Case; Upper to Lower Case */
static inline char *case_swap(char *in) {
for (int i = 0; in[i] != '\0'; i++)
if (isalpha(in[i]))
in[i] ^= ascii_x;
return in;
}
#define LEN 50
#define str(x) # x
#define xstr(x) str(x)
static char buf[LEN];
int main() {
/* Ensure that there is no buffering for stdin. */
setbuf(stdin, NULL);
/* discard the input stream upto but not including the newline
* character. Extra getchar() is required to consume this.
*/
scanf("%"xstr(LEN)"[^\n]%*[^\n]", buf);
getchar();
/* TODO: error handling such as EOF */
printf("Orig: %s\n", buf);
printf("New: %s\n", case_swap(buf));
return 0;
}
===這裡結束===
以 GNU/Linux 為例,編譯和執行方式如下: (省略開頭的 '$ ')
$ gcc -o X X.c -Wall
$ ./X
參考輸入: abcde (記得按下 Enter)
參考輸出:
Orig: abcde
New: ABCDE
可隨機產生字串來測試程式,方法如下: (省略開頭的 '$ ')
$ (cat /dev/urandom | tr -dc 'a-zA-Z0-9' | fold -w 10 | head -n 1) | ./X
參考輸出:
Orig: MeXKS1VMOi
New: mExks1vmoI
上述程式仍有改進空間,隨意列出:
1. 缺乏對於 EOF 的處理;
2. 程式碼忽略超出 50 個字元 (正確來說還要減去 NULL terminator) 的處理,但可能會跟使用者期望有落差;
3. 考慮到 secure coding (安全可靠的程式設計方式),應該重新包裝 buffered I/O 函式,讓日後重用;
歡迎一起學習 C 語言程式設計:
http://hackfoldr.org/dykc/
「會 C、會呼吸」即可「成為電腦的主人」,做自己,好自在。
--
--
※ 發信站: 批踢踢實業坊(ptt.cc), 來自: 220.133.113.20
※ 文章代碼(AID): #1Pekbefg (Gossiping)
※ 文章網址: https://www.ptt.cc/bbs/Gossiping/M.1503848808.A.A6A.html
→ Refauth: ......................2F 08/27 23:47
推 eris231: jserv ....3F 08/27 23:47
→ Refauth: 又來亂搞了.........6F 08/27 23:48
推 alan23273850: 大神親自下凡來指導啦!!!!!還免學費,原PO真的要好好珍惜阿!!!!!!!!!!!!!!!!!!9F 08/27 23:48
推 isa: 媽~~我看到jserv了!11F 08/27 23:49
→ s860134: 還是去學 python 嘻嘻12F 08/27 23:49
推 Archier: 又在浪費才能了.....15F 08/27 23:49
→ isa: 有神快拜!16F 08/27 23:50
→ s860134: ID當然是本人阿..20F 08/27 23:51
推 XXXXSHIT: 看完以後好暈 不是有簡單的寫法?27F 08/27 23:54
→ jserv: Brabus700G, 對呀,所以趕快來自幹 JVM28F 08/27 23:54
推 ycix: 靠杯 是本人 有神快拜31F 08/27 23:56
推 KNVSEOC: 大大 容許我跪一下嗎43F 08/28 00:02
推 dexdey: 拜神 普渡一下46F 08/28 00:03
推 tanby: 神降臨53F 08/28 00:11
推 stiles: 靠杯, 大神回文!55F 08/28 00:11
→ alan23273850: 一開始執行的時候應該也不會輸入殘留,所以setbuf其實不必要?60F 08/28 00:12
推 olctw: 有神快拜 <(_ _)>62F 08/28 00:13
推 BoXeX: 大概是fork出來的??63F 08/28 00:13
推 Argos: 唉 語法真的不是很人性化就是了 雖然還是得用69F 08/28 00:16
推 penolove: 有理, 假設自幹bash, fork時stdin有可能殘留70F 08/28 00:16
推 alan23273850: 感謝BoXEX大提點 不過這整支獨立程式應該不會有fork的行為出現?71F 08/28 00:16
推 hw102050: 媽別問 我一定要跪著看這篇文75F 08/28 00:17
推 fransice7: ...................................................79F 08/28 00:19
→ jserv: alan23273850, 請考慮 pipe 的使用
為了避免直接被拿去當作業,我的程式碼做了一點「加工」80F 08/28 00:19
推 jaid: 媽我在這82F 08/28 00:20
推 opthr1215: in ^= ascii_x; 有點神83F 08/28 00:22
推 loet: 神人推87F 08/28 00:26
推 vi000246: 原本以為是廢文 結果到ID跪了88F 08/28 00:27
推 heary: 有神快拜94F 08/28 00:28
推 knaw: 神串留名95F 08/28 00:28
推 JameC: 這寫法有多少人知道啊...100F 08/28 00:32
推 CJROCK: 神到不敢修神的課101F 08/28 00:32
推 a5480277: 坦白說 如果作業看到scanf那種寫法 就知道copy的了110F 08/28 00:36
推 Marssa: 釣到大魚了....111F 08/28 00:37
推 yongb: scanf那個正規化大學生用不出來吧113F 08/28 00:37
推 Leony: 我在這裡~~~~^_^114F 08/28 00:38
推 Remedy: 好像蠻猛115F 08/28 00:38
推 wkunhui: 娘子快出來拜神啦116F 08/28 00:38
推 JameC: 這種去專版問可能會把噓的,在這裡竟然吊得到高手,也是很妙
*被117F 08/28 00:39
推 yongb: 我是覺得啦,怎沒人順帶解釋一下原po為何會亂碼??121F 08/28 00:39
推 opthr1215: 原文底下推文就有講了,哪會沒人解釋。
亂碼的原因就是原po把字尾也改掉了。122F 08/28 00:40
推 ayueh: 朝聖推 老師好127F 08/28 00:43
推 yongb: 原來是這樣,剛剛去爬惹131F 08/28 00:44
推 Assisi: 是 jserv 大大 (拜136F 08/28 00:46
推 shiwa: 朝聖139F 08/28 00:47
推 NewPassat: 每個compiler不一樣,不見得你用的toolchain就會幫你把mem都清乾淨,我就遇過一開始stack都是髒的。142F 08/28 00:50
推 mia3: 推推~~~>_<146F 08/28 00:54
推 bloodruru: 站上臥虎藏龍 有些人卻老喜歡戰版友 XD147F 08/28 00:54
推 TUTOTO: 我都用 gcc -O3149F 08/28 00:56
推 kig88: 這學期衝堂選不到課QQ156F 08/28 01:08
推 weboau: 有神先噓160F 08/28 01:14
推 einejack: 看完只會像操拎呆一樣蛤XD162F 08/28 01:15
推 yuu101: 有神快拜163F 08/28 01:15
推 Everforest: 文言文都廢掉拿來上這個多好 有意義太多了164F 08/28 01:19
推 aphrodite98: 我剛還在想 誰啊! 估狗後.....挖賽...隔行隔山啊166F 08/28 01:20
推 attis: 神來了167F 08/28 01:23
推 TheWho: 大神!! jserv173F 08/28 01:26
推 iamtu: 神串留名176F 08/28 01:31
推 ChoDino: 這樣拿去交作業助教會看不懂阿!釣到TW C語言第一把交椅182F 08/28 01:39
噓 dzwei: 幫C++STL QQ
然後看到神還是得推188F 08/28 01:51
推 rehtra: 靠!好神啊!天啊天啊!196F 08/28 02:06
推 saiulbb: 靠邀 這不是JSERV大大嗎 扯197F 08/28 02:08
推 wei115: 有神快拜203F 08/28 02:15
推 lpoijk: 哇 娘子快出來看上帝208F 08/28 02:23
推 xunhuiwu: 快拜!不然人家以為我看不懂!XDD209F 08/28 02:23
推 atbb: 朝聖~213F 08/28 02:37
推 afs479632: 這寫法真的第一次看到 跪了......214F 08/28 02:39
推 a2881105: 台灣語言的第一把交椅還不敢快來拜216F 08/28 02:44
→ alan23273850: 是說剛剛經過老師指點之後,又寫了程式跑了一下,的確 pipe 會讓前一階的輸出變成後一階的輸入,但現在尷尬的是不論用什麼方法都沒辦法把前一階送進來的input 洗掉,包括老師的 setbuf ...... 這實在太詭異了。如果重複 scanf,就會重複吃前一階送進來的字221F 08/28 02:52
→ alan23273850: 串,中間印出來之後也不會把 buffer 清空,一整個黑人問號 XD 空前絕後始料未及227F 08/28 02:55
推 alan23273850: 大家也不妨串接 pipe 跑跑看,說不定有驚人發現 XD老師的精神真的值得我們學習230F 08/28 02:59
→ jserv: alan2327385: 感謝實驗,你需要加 if (feof(stdin)) {...}各位網友,只有作古的人物才會神化,那當然是C語言老爸dmrdmr = Dennis M. Ritchie, C 語言和 UNIX 共同發明者
我寫報告搞得失眠,看到有人這麼認真討論,我順手回覆
希望大家勿輕視buffered I/O背後的學問,絕非「大一就會」這可有多變形,細節涉及資訊安全、作業系統,甚至計算理論(原來不能噓自己/ 我程式寫不好,當然要接受大家批評)235F 08/28 03:06
推 yao860718: 朝聖!!就從今天起 開始學C語言!!242F 08/28 03:17
推 ksjr: 網站看起來很強大!246F 08/28 03:32
推 wu6u3: 釣到神人了247F 08/28 03:48
推 ttping: 有神!!249F 08/28 04:13
→ IsadQQ56: 原來可以這樣用define@@ 學了一課255F 08/28 04:58
推 IsadQQ56: 從大一學到現在對UNIX都沒什麼接觸,不太懂用commandline產生random那段
也看不懂scsnf QQ
*scanf258F 08/28 05:03
噓 Anikk: 文組啦264F 08/28 05:20
推 EGMMA: 推265F 08/28 05:23
噓 andyiron: 原來是live coding 神,噓一下覺的開心268F 08/28 05:52
→ a8989332: ....................................................274F 08/28 07:34
推 joewu8267: 這平凡無奇的餌,兒竟然會中大魚~276F 08/28 07:47
推 tw88: 天啊媽我在這...284F 08/28 08:25
推 StevenAn: 這什麼碗糕啊!!? 會C++可以拿來買菜嗎286F 08/28 08:27
推 nfsnfs: jserv!!!290F 08/28 08:36
噓 b81314: 很神 但在這邊問C真的浪費版面292F 08/28 08:43
推 MoonByul: 以後可能有類似作業
先卡個296F 08/28 08:51
推 vdfoty: 最近很多跑錯版的 奇怪300F 08/28 09:05
推 bomda: 朝聖一下305F 08/28 09:33
推 jssmile: JERV~~~~~307F 08/28 09:34
→ soyjay: 現在流行在八卦版問作業?308F 08/28 09:35
→ Siu: 為甚麼^=32..310F 08/28 09:39
推 mdkn35: 當你還在研究C怎麼寫 java已經把功能都做好了315F 08/28 10:00
推 ryk: 有神快拜!318F 08/28 10:31
推 achihc: 快推,不然別人以為不會寫程式320F 08/28 10:52
推 ernova831: 啊啊啊啊啊看不懂還是跪下來拜一下323F 08/28 11:05
→ Wand …
推 Wand: 。。。。。325F 08/28 11:27
推 megxz: 學會C語言327F 08/28 11:56
推 vxior: 朝聖329F 08/28 12:11
推 ggBird: 因為大小寫相差了 32330F 08/28 12:12
推 gncn: 跪332F 08/28 12:51
推 kersihi: 這餌居然可以釣到神......先跪再說338F 08/28 14:09
推 bluefire: 太扯了這樣也能請超級大師出來。。。341F 08/28 15:00
推 ajneok: 朝聖!有神快拜 m(_ _)m347F 08/28 16:10
推 OOQ: 你是在認真什麼啦348F 08/28 16:25
推 jj782995: 先拜再說 雖然我比較喜歡D350F 08/28 16:52
推 iamten: 八掛能學C 你敢信!!351F 08/28 17:07
→ Kitakami: 77777777777777352F 08/28 17:33
推 alan23273850: 哇哈哈終於完全弄懂啦!!!花了兩、三小時多。原來我一開始就誤會老師的code了,老師一開始的setbuf其實是設定buffer的模式,而不是把之前緩衝區的內容清空。那如果是在pipe的情況下,想要直接取pipe傳過來的文字,當然要使用while(scanf(...)!=EOF),這跟online judge一樣,如果不檢查EOF,stdin則會保留最後一行文字。簡單來說,scanf吃檔案的時候不管有沒有EOF不會停,只有吃鍵盤輸入時才會暫停等使用者輸入。那如果在pipe的情況下堅持要吃鍵盤輸入,就只能使用freopen了,會把stdin改為鍵盤,並摒棄之前的暫存。
這篇文真der讓我獲益良多RRRRRRRRRRRR354F 08/28 18:47
推 goldie: jserv 大神出現!!!… <(__ __)>366F 08/28 19:01
推 alan23273850: 不過我後來想一想也蠻有道理的,如果scanf的stdin交給檔案輸入,遇到eof又暫停的話,整支程式就會卡住了,難怪要這樣設計。只能說C語言博大精深啊!370F 08/28 20:36
→ lai526: 有神快拜~ 敬群學長好!373F 08/28 21:01
推 ekgs: 你可以自幹一個scanf(誤)376F 08/28 21:49
→ jserv: alan23273850: 再次感謝心得分享,方便寫篇短文紀錄嗎?
為了避免貼文離題,本文是「有沒有在八卦版學C的八卦?」386F 08/29 09:26
推 pshuang: 這是C++ 不是C啦388F 08/29 09:28
→ jserv: 承上「有沒有大學課程在八卦版廣告的八卦?」
(上述課程網頁的瀏覽數量在24小時內增加近4000人次)389F 08/29 09:36
推 gusony: 神串留名 scanf那邊看不懂 有大大能解釋嗎?392F 08/29 14:30
推 pcyu16: 推推推推推393F 08/29 14:40
→ ekgs: 簡單的說 是為了處理換行字元395F 08/29 19:35
--