คลังเก็บป้ายกำกับ: C

Schlemiel the Painter

นาย Schlemiel เป็นช่างทาสี เขารับงานตีเส้นถนน

วันแรกทาสีได้ 300 เมตร หัวหน้าเขาก็ชมว่า “เยี่ยมมากเลย”
วันที่สองทาสีได้ 150 เมตร หัวหน้าบอกว่า “อืม ก็ยังโอเคอยู่นะ”
วันที่สามทาสีได้ 30 เมตร หัวหน้าเขาบอก “เฮ้ย นี่มันใช้ไม่ได้เลยนะเนี่ย วันแรกแกตีได้มากกว่านี้ตั้ง 10 เท่า”

ช่างทาสีบอกว่า “ช่วยไม่ได้นี่นา ก็กระป๋องสีมันอยู่ไกลจากฉันมากขึ้น มากขึ้นทุกวัน”

เขาวางกระป๋องสีไว้ที่จุดเริ่มต้น โดยไม่ได้ย้ายมันตามมา เขาจึงต้องเดินกลับไปไกลขึ้นๆ ทุกครั้งที่เดินกลับไปจุ่มแปรงสี

เรื่องนี้แต่งขึ้นโดย Joel Spolsky เพื่อเลียนแบบพฤติกรรมของ C String ที่การ concatenate ทำได้ช้า เพราะต้องวิ่งจากหัว string ไปจนสุด string ก่อนทุกครั้ง ถึงจะหาตำแหน่งเพื่อเขียน string ต่อท้ายได้ครับ

อ่านเพิ่มได้ใน http://en.m.wikipedia.org/wiki/Schlemiel_the_Painter’s_algorithm

เขาทำ progress ใน terminal กันยังไงหว่า?

เคยเรียกคำสั่งอะไรใน terminal แล้วมันก็ขึ้นเลข 0%, 10%, 20%, … 100% ใน terminal ไหม (มันอัพเดทข้อความในบรรทัดเดิมได้เรื่อยๆ… มันทำยังไงหว่า?)

อ่ะนี่ ตัวอักษรสำคัญเลขคือ r (carriage return)

#include <stdio.h>
void delay()
{
   for(int i=0;i&lt;1000000;i++) for(int j=0;j&lt;10;j++);
}
int main()
{
   for(int p=0;p&lt;=100;p++)
   {
       delay();
       printf(&quot;rPercent: %d &quot;, p);
       fflush(stdout);
   }
   printf(&quot;n&quot;);
   return 0;
}

งืมๆ… มาพ่นโค้ด แล้วก็ไป ฮ่าๆ

ปลั๊กอิน “ป้องกัน SPAM” สำหรับ pidgin

msn_spamเบื่อ SPAM ทาง msn มาก! จะบล็อกคนส่งทิ้งแบบ @rtsp ก็ใจร้ายเกินไป

ผมเลยลองเขียนปลั๊กอินไว้ “กรองข้อความ” โดยใช้เงื่อนไขง่ายๆ ว่า

“ใน 1 ชม. ที่ผ่านมา ถ้าเธอยังไม่เคยส่งข้อความหาฉันเลย แล้วจู่ๆ ส่ง URL มาให้ ฉันจะขอโยนข้อความนั้นทิ้งซะ (มันต้องเป็น spam แน่เลย!)”

อ่านเพิ่มเติม ปลั๊กอิน “ป้องกัน SPAM” สำหรับ pidgin

ไปค่ายทะลุฟ้า (eXceed#6)

นอนเล่นคอมฯคนที่ follow @nattster ในช่วงเดือนที่ผ่านมาจะเห็นผมบ่นถึงค่าย eXceed#6 บ่อยๆ เมื่อผมกลับจากค่ายก็เห็นพี่ๆ เพื่อนๆ หลายคนบล็อกถึงค่ายนี้ (ป๊อบ, จ๊อบ, พี่ออฟ) เลยรู้สึกอยากเขียนบล็อกบ้าง… (บล็อกตามกระแส)

Q: eXceed Camp หรือค่ายทะลุฟ้าคืออะไร?
A: ค่าย 7 วันสำหรับนิสิตที่กำลังจะขึ้นปี 2 จากวิศวคอมฯ บางเขน+กำแพงแสน+วิศวซอฟต์แวร์ ประมาณ 120 คนมานั่งเรียน….จัดกลุ่มประมาณ 7-8 คนแล้วให้ลองเขียนโปรแกรมด้วยกันภายในเวลา 2 คืน 1 วัน

จะเห็นว่าเดือนที่แล้ว ผมไม่ได้เขียนบล็อกเลย เพราะนั่งคุย นั่งเตรียมค่ายกับเพื่อนๆ ปี 3 แล้วก็ อ่านเพิ่มเติม ไปค่ายทะลุฟ้า (eXceed#6)

กลับลำดับ Bit ในตัวแปร Integer

วันนี้เขียน Micro C ลง dsPIC30 (เป็น Microcontroller ตัวนึงน่ะนะ) ต้องการเขียนโปรแกรมให้กลับลำดับ bit ในตัวแปร x

x = 01001111000000001010101011110000

ให้กลายเป็น

y = 00001111010101010000000011110010

(คือ เขียน bit ใน x จากหลังมาหน้านั่นแหละครับ)

ตอนแรกพยายามนึกวิธีเอง ได้วิธีถึกๆ แบบต้องวนลูป 32 ครั้งค่อยๆ ดึง bit ตัวท้ายออกมาใส่อีกตัวแปรนึงไปเรื่อยๆ (32 ครั้ง = 32 bit) พอไปค้นในเน็ตเจอ Bit Twiddling Hacks ซึ่งแข็งแกร่งมาก (ทำเสร็จในไม่กี่ operation) ขอเอาโค้ดมาแปะตามนี้
อ่านเพิ่มเติม กลับลำดับ Bit ในตัวแปร Integer

Mysweeper version 1 ชม. เสร็จ

mysweeperวันนี้ขอนำเสนอเกมส์ Mysweeper ซึ่งมันก็เป็นเกมส์แบบเดียวกับ Minesweeper ที่เราเล่นกันมานาน (ตั้งชื่อแบบนี้จะได้ออกเสียงคล้าย Minesweeper ต้นฉบับ) แต่ถ้าแปลตรงตัวก็น่าจะแปลว่า “ไม้กวาด ของฉัน” ฮ่าๆ

เกมส์ Mysweeper เป็นเกมส์ที่ปั่นอย่างบ้าระห่ำ ใน 1 ชม. (ไม่ยอมอ่านหนังสือสอบ) เพื่อที่จะเอาไปบอกน้องๆ ปีหนึ่งว่า นี่คือเกมส์เล็กๆ ที่สร้างด้วย Visual C# ได้นะครับ (ผมกำลังจะสอนน้องๆ เรื่อง Windows Form Application ครับ)

แต่เขียนเสร็จเก็บไว้มันก็เท่านั้น เอาโค้ดมาแจกละกันครับ เผื่อใครจะลองเอาไปศึกษาดู อ่านรู้เรื่องไม่รู้เรื่องก็ทิ้ง comment ไว้ได้นะครับ สาเหตุที่เอาโค้ดมาแจกเพราะตอนสมัยหัดเขียน Visual Basic ครั้งแรกๆ ก็มาดาวน์โหลดโค้ดชาวบ้านไปนั่งดู (เยอะมากๆ) โค้ดอันนึงที่ประทับใจมากคือโค้ดของ Tamagotchi Simulator ของคุณ Tooh (พีรภัทร์ สว่างเพียร) แล้วเอามานั่งแกะๆ แล้วได้รับความรู้มากมาย

ผมเลยหวังว่าโปรแกรมเล็กๆ ที่ผมเขียนนี้อาจจะเป็นแหล่งเรียนรู้ให้กับคนอื่นได้ไม่มากก็น้อยฮับ

ดาวน์โหลดโค้ดเกมส์ mysweeper (ขนาด 46KB สร้างด้วย Visual Studio 2008)

ฟังก์ชัน printbin

วันนี้ก็อ่านหนังสือสอบวิชา Abstract Data Type แล้วก็เปิดเว็บบอร์ดรุ่นไปพลางๆ ก็เจอ @b4lmung สงสัยว่าผลลัพธ์ที่ได้จากโค้ด printf ต่อไปนี้มันเอาส่วนไหนของ float มา print

#include 
int main(){
      float a = 10.1F;
      printf("%d", a);
      return 0;
}
Result:
1073741824

เราก็เกิดอาการสงสัย และเดาว่า มันคงอ่านค่า binary ทั้งดุ้นของ float เป็นแบบ int และพิมพ์ออกมา เราก็เลยลองฟังก์ชัน printbin เพื่อพิมพ์ binary representation ของตัวแปรใดๆ (ดูว่าใน ram มันเก็บเป็นเลขฐานสองยังไง) ได้โค้ดอย่างนี้…

#include 
void printbin(char *c, int bytes)
{  // author: nattster.siamdev.net
  int i, j;
  char a;
  for(j=bytes-1; j>=0; j--)
  {
    a = c[j];
    for(i=sizeof(char)*8-1; i>=0; i--)
    {
      printf("%d", (((a & 1< 0) ? 1 : 0));
    }
  }
  printf("n");
}
int main(){
  float a = 10.1F;
  printf("%dn", a);
  printbin((char*)&a, sizeof(float));
  return 0;
}
Result:
1073741824
01000001001000011001100110011010

เลขฐานสองยาวๆ อันล่างเป็น binary representation ของ 10.1F ตามมาตรฐาน IEEE754-1985 พอลองแปลงเลขฐานสองก้อนนี้กลับไปเป็นฐานสิบมันได้ = 1092721050 ซึ่งคลาดเคลื่อนจากผลที่ได้จาก printf(“%d”, a); นิดหน่อย สรุปว่าเราก็ยังไม่รู้อยู่ดีว่า printf มันเอาอะไรออกมาพิมพ์

แต่! ได้ฟังก์ชัน printbin เอาไว้ใช้เป็นของเล่นในอนาคต เผื่ออยากดูว่าตัวแปรอื่นๆ มันเก็บข้อมูลใน memory ยังไง

ปล. คิดว่าฟังก์ชันทำงานถูกต้องแล้วนะ เพราะลองใส่เลข 0.15625 แล้วมันได้เลขฐานสองถูกต้องตามรูปนี้อ่ะ

IEEE754 representation of 0.15625 (Ref: wikipedia.org)
IEEE754 representation of 0.15625 (Ref: wikipedia.org)

ปล2. ลองใช้ฟังก์ชัน printbin เช็คดูว่าจำนวนเต็มติดลบ มันจะเก็บเป็น 2’complements อย่างที่เราเรียนๆ มากันรึเปล่า

ปล3. ช่วงนี้มีแต่ภาษา C และเลขฐานสอง เพราะกำลังจะสอบวิชา Abstract Data Types และ Digital ฮ่าๆ

calloc VS. malloc

นั่งเรียนเขียนโปรแกรมภาษาซี มาก็หลายอาจารย์ หลายรอบ แต่วันนี้เพิ่งจะรู้ว่าฟังก์ชัน calloc กับ malloc ต่างกันยังไง ตอนเรียน อ.ก็บอกว่า ทั้งสองฟังก์ชันทำหน้าที่จองหน่วยความจำให้ตามที่เรากำหนด แต่วิธีเรียกใช้ต่างกันนิดหน่อย

malloc(ขนาดหน่วยความจำเป็นไบต์);
calloc(หน่วยความจำกี่ช่อง, ช่องละกี่ไบต์)

เกิดอาการสงสัยอย่างแรง ว่าไหนๆ มันก็ทำงานได้เหมือนๆ กันแล้ว ทำไมต้องมีตั้งสองฟังก์ชัน พอไปเปิด man ดูก็เจอข้อแตกต่างว่า malloc จะจองพื้นที่ให้ แล้วก็จบแค่นั้น แต่ calloc จะจองพื้นที่ให้และกำหนดค่าเริ่มต้นเป็น 0 ด้วย

ลองดูโค้ดและผลลัพธ์ของโปรแกรม น่าจะช่วยให้เข้าใจง่ายขึ้นครับ

#include <stdio.h>
#include <stdlib.h>
int main() {
	int *a = (int*) malloc(sizeof(int)*10);
	int *b = (int*) calloc(10, sizeof(int));
	int i;
	for(i=0;i < 10;i++)
	{
		printf("a = %d, b = %d\n", a[i], b[i]);
	}
	return 0;
}

ผลลัพธ์:

a = 3221200, b = 0
a = 3215048, b = 0
a = 1095651909, b = 0
a = 1346192717, b = 0
a = 1095910725, b = 0
a = 1196314448, b = 0
a = 1866661971, b = 0
a = 1701860205, b = 0
a = 977485155, b = 0
a = 1852397404, b = 0

ดังนั้นควรเลือกฟังก์ชันให้เหมาะสมกับการใช้งาน เพราะมี overhead ไม่เท่ากันนะครับ

ใช้ man ดู Function Reference ภาษาซีใน ubuntu

คนใช้ linux (หรือ cygwin ก็ด่ะ) น่าจะรู้จักคำสั่ง man ที่เอาไว้ใช้ดู manual ของคำสั่งต่างๆ ใน linux
ท่านผู้อ่าน รู้หรือไม่ว่า? เราสามารถใช้คำสั่ง

$ man qsort

เพื่อดูรายละเอียดของฟังก์ชัน qsort ได้ผลลัพธ์ตามนี้ (ทีนี้จะได้รู้และว่าต้อง include file ไหนและฟังก์ชันรับอาร์กิวเมนท์อะไรบ้าง)

QSORT(3)                   Linux Programmer`s Manual                  QSORT(3)

NAME
       qsort - sorts an array

SYNOPSIS
       #include 

       void qsort(void *base, size_t nmemb, size_t size,
                  int(*compar)(const void *, const void *));

DESCRIPTION
       The  qsort()  function sorts an array with nmemb elements of size size.
       The base argument points to the start of the array.

แต่! ก่อนที่จะทำแบบนี้ได้ต้องติดตั้งแพคเกจ manpages-dev ก่อนครับ สำหรับผู้ใช้ ubuntu/debian (ใช้ Synaptic ติดตั้ง หรือ sudo apt-get install manpages-dev ก็ได้ครับ) สำหรับคนใช้ดิสโทรอื่นต้องลองค้น google ดูครับ

ถ้าลอง man printf ดูจะเจอ manual ของคำสั่ง printf ของ linux แทนที่จะเป็น reference ของฟังก์ชัน printf ของภาษา C แทน

วิธีเปิด manual ของ printf (ฟังก์ชันภาษา C) ให้เรียกคำสั่ง

$ man 3 printf

แทน ซึ่งหมายความว่า เปิดดูคำสั่ง printf ใน section ที่ 3 ของ manual ครับ (manual มีทั้งหมด 7-8 section… เขาแบ่ง section ตามหัวข้อครับ ดูรายละเอียดเพิ่มเติมที่นี่)

วนลูป แล้วลบ “ของ” ออกจาก list

คุณเคยต้องเขียนโปรแกรมที่วนลูปบน list แล้วลบ “ของ (object)” ออกจาก list นั้นหรือไม่? ลองยกตัวอย่างโปรแกรมง่ายๆ สมมติให้ list A เก็บเลขจำนวนเต็ม แล้วคุณต้องการลบเลขที่หารสามลงตัว ออกจาก list A โค้ดของคุณก็อาจจะเป็น

Python C#
A = [1, 2, 3, 6, 7, 9, 12]
for x in A:
    if x % 3 == 0:
        A.remove(x)

List A = new List(new int[]{1, 2, 3, 6, 7, 9, 12});
foreach(int x in A)
{
    if(x % 3 == 0)
        A.Remove(x);
}

ในบล็อกนี้ขออนุญาตยกตัวอย่างแค่ 2 ภาษา คือ Python และ C# นะครับ สำหรับฝั่ง C# จะเจอกับ “Unhandled Exception: System.InvalidOperationException: Collection was modified;” (เขาบอกว่า เกิดการกระทำที่ไม่ถูกต้อง เนื่องจาก list ถูกแก้ไขระหว่างวนลูป) ส่วนคนใช้ Python จะไม่เจอปัญหาอะไรเวลารันครับ แต่พอลองพิมพ์ A ออกมาดูจะพบว่า

A = [1, 2, 6, 7, 12]

แงว… ทำไม 6 กับ 12 ยังโผล่ออกมา? ในเมื่อมันน่าจะ mod 3 ลงตัว… ในบล็อกนี้เราจะมาดูวิธีแก้ปัญหาที่มักจะเจอบ่อยๆ ปัญหานี้กันครับ

อ่านเพิ่มเติม วนลูป แล้วลบ “ของ” ออกจาก list