<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:wfw="http://wellformedweb.org/CommentAPI/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:atom="http://www.w3.org/2005/Atom"
	xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
	xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
	xmlns:georss="http://www.georss.org/georss" xmlns:geo="http://www.w3.org/2003/01/geo/wgs84_pos#" xmlns:media="http://search.yahoo.com/mrss/"
	>

<channel>
	<title>Vietnamese Developers' Blog &#187; Programming</title>
	<atom:link href="http://openandfree.wordpress.com/category/programming/feed/" rel="self" type="application/rss+xml" />
	<link>http://openandfree.wordpress.com</link>
	<description>There are 10 types of people in the world: Those who know the binary system and those who don't</description>
	<lastBuildDate>Sat, 22 Nov 2008 00:47:09 +0000</lastBuildDate>
	<generator>http://wordpress.com/</generator>
	<language>en</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
	<cloud domain='openandfree.wordpress.com' port='80' path='/?rsscloud=notify' registerProcedure='' protocol='http-post' />
<image>
		<url>http://www.gravatar.com/blavatar/caa4770bbad32f97d95cfd98b414dfc1?s=96&#038;d=http://s.wordpress.com/i/buttonw-com.png</url>
		<title>Vietnamese Developers' Blog &#187; Programming</title>
		<link>http://openandfree.wordpress.com</link>
	</image>
			<item>
		<title>Gọi repaint() nhiều lần trong JFrame và JApplet</title>
		<link>http://openandfree.wordpress.com/2008/11/22/g%e1%bb%8di-repaint-nhi%e1%bb%81u-l%e1%ba%a7n-trong-jframe-va-japplet/</link>
		<comments>http://openandfree.wordpress.com/2008/11/22/g%e1%bb%8di-repaint-nhi%e1%bb%81u-l%e1%ba%a7n-trong-jframe-va-japplet/#comments</comments>
		<pubDate>Sat, 22 Nov 2008 00:47:09 +0000</pubDate>
		<dc:creator>kiennguyen</dc:creator>
				<category><![CDATA[Java]]></category>
		<category><![CDATA[frame]]></category>
		<category><![CDATA[repaint()]]></category>

		<guid isPermaLink="false">http://www.openandfree.org/blog/?p=78</guid>
		<description><![CDATA[Khi học Java, chúng ta thường bắt gặp những chương trình đơn giản về animation trong các sách dạy AWT và Swing, chẳng hạn như chương trình sau đây:
import java.awt.*;
import javax.swing.*;

public class Animation1 {

  public static void main( String[] args ) {

     Animation1 gui = new Animation1();
    [...]<img alt="" border="0" src="http://stats.wordpress.com/b.gif?host=openandfree.wordpress.com&blog=1590880&post=93&subd=openandfree&ref=&feed=1" />]]></description>
			<content:encoded><![CDATA[<div class='snap_preview'><br /><p style="text-align:justify;">Khi học Java, chúng ta thường bắt gặp những chương trình đơn giản về animation trong các sách dạy AWT và Swing, chẳng hạn như chương trình sau đây:</p>
<pre>import java.awt.*;
import javax.swing.*;

public class Animation1 {

  public static void main( String[] args ) {

     Animation1 gui = new Animation1();
     gui.go();

  }

  private void go() {

     JFrame frame = new JFrame();
     frame.setDefaultCloseOperation( JFrame.EXIT_ON_CLOSE );

     panel_ = new MyPanel();
     frame.getContentPane().add( panel_, BorderLayout.CENTER );

     frame.setSize( 500, 500 );
     frame.setVisible( true );

     for( int i = 0; i &lt; 400; i++ ) {

        x_++;
        y_++;

        panel_.repaint();

        try {
          Thread.sleep( 10 );
        } catch( Exception ex ) { }

     }

  }

  class MyPanel extends JPanel {

     public void paintComponent( Graphics g ) {

         g.setColor( Color.white );
         g.fillRect( 0, 0, this.getWidth(), this.getHeight() );

         g.setColor( Color.green );
         g.fillOval( x_, y_, 40, 40 );

     }

  }

  private JPanel panel_;
  private int x_ = 0;
  private int y_ = 0;

}</pre>
<p style="text-align:justify;">Chương trình này vẽ ra một vòng tròn trên một panel, tính toán lại tọa độ của nó rồi gọi repaint() để vẽ lại vòng tròn. Phương thức repaint() yêu cầu các component trên frame tự vẽ lại.Thao tác vẽ lại liên tục với các vị trí khác nhau sẽ tạo ra cảm giác vòng tròn chạy trên panel. Câu lệnh Thread.sleep(10) làm giảm tốc độ di chuyển của vòng tròn giúp người dùng dễ theo dõi.</p>
<p style="text-align:justify;">Chúng ta thử sáng tạo thêm một chút bằng cách thêm vào frame một button dùng kể kích hoạt animation (học event handler và inner class luôn). Animation sẽ được kích hoạt khi người dùng ấn nút &#8220;Start animation&#8221;. Chương trình được cải tiến như sau:<span id="more-93"></span></p>
<pre>import java.awt.*;
import java.awt.event.*;
import javax.swing.*;

public class Animation2 {

    public static void main( String[] args ) {

	Animation2 gui = new Animation2();
	gui.go();

    }

    private void go() {

	JFrame frame = new JFrame();
	frame.setDefaultCloseOperation( JFrame.EXIT_ON_CLOSE );

	panel_ = new MyPanel();
	frame.getContentPane().add( panel_, BorderLayout.CENTER );

	button_ = new JButton( "start animation" );
	button_.addActionListener( new StartAnimationAction() );
	frame.getContentPane().add( button_, BorderLayout.SOUTH );

	frame.setSize( 500, 500 );
	frame.setVisible( true );

    }

    class MyPanel extends JPanel {

	public void paintComponent( Graphics g ) {

	    g.setColor( Color.white );
	    g.fillRect( 0, 0, this.getWidth(), this.getHeight() );

	    g.setColor( Color.green );
	    g.fillOval( x_, y_, 40, 40 );

	}

    }

    class StartAnimationAction implements ActionListener {

	public void actionPerformed( ActionEvent e ) {

	    for( int i = 0; i &lt; 400; i++ ) {

		x_++;
		y_++;

		panel_.repaint();

		try {
		  Thread.sleep( 10 );
		} catch( Exception ex ) { }

	    }

	}

    }

  private JPanel panel_;
  private JButton button_;
  private int x_ = 0;
  private int y_ = 0;

}</pre>
<p style="text-align:justify;">Phiên bản mới nhìn qua thì rất &#8220;đẹp&#8221;, nhưng thực ra nó không chạy đúng như chúng ta mong đợi!  Chúng ta không nhìn thấy vòng tròn di chuyển trên panel mà chỉ thấy nó nhảy  từ vị trí ban đầu đến vị trí cuối cùng, các trạng thái trung gian đã bị mất. Vậy đâu là nguyên nhân của hành vi kì lạ này?</p>
<p style="text-align:justify;">Thực ra, khi chúng ta đặt phương thức repaint() vào trong một vòng lặp, AWT sẽ trộn các lời gọi repaint() lại với nhau và chỉ có lời gọi repaint() cuối cùng được thực hiện. Bởi vậy chúng ta không thể nhìn thấy các trạng thái trung gian của vòng tròn trên panel.</p>
<p style="text-align:justify;">Vậy làm thế nào giải quyết vấn đề này? Một giải pháp là đưa các lời gọi repaint() sang một thread khác như sau:</p>
<pre>import java.awt.*;
import java.awt.event.*;
import javax.swing.*;

public class Animation3 {

    public static void main( String[] args ) {

	Animation3 gui = new Animation3();
	gui.go();

    }

    private void go() {

	JFrame frame = new JFrame();
	frame.setDefaultCloseOperation( JFrame.EXIT_ON_CLOSE );

	panel_ = new MyPanel();
	frame.getContentPane().add( panel_, BorderLayout.CENTER );

	button_ = new JButton( "start animation" );
	button_.addActionListener( new StartAnimationAction() );
	frame.getContentPane().add( button_, BorderLayout.SOUTH );

	frame.setSize( 500, 500 );
	frame.setVisible( true );

    }

    class MyPanel extends JPanel {

	public void paintComponent( Graphics g ) {

	    g.setColor( Color.white );
	    g.fillRect( 0, 0, this.getWidth(), this.getHeight() );

	    g.setColor( Color.green );
	    g.fillOval( x_, y_, 40, 40 );

	}

    }

    class StartAnimationAction implements ActionListener, Runnable {

	public void actionPerformed( ActionEvent e ) {

	    Thread thread = new Thread( this );
	    thread.start();

	}

	public void run() {

	    for( int i = 0; i &lt; 400; i++ ) {

		x_++;
		y_++;

		panel_.repaint();

		try {
		  Thread.sleep( 10 );
		} catch( Exception ex ) { }

	    }

	}

    }

  private JPanel panel_;
  private JButton button_;
  private int x_ = 0;
  private int y_ = 0;

}</pre>
<p>Bây giờ thì chương trình của chúng ta đã chạy ngon lành. Để giải thích cặn kẽ về vấn đề gọi repaint() nhiều lần có lẽ cần đến những hiểu biết nhất định về thread trong Java. Bởi vậy &#8220;tác giả&#8221;, với trình độ còn rất hạn chế, đành tạm thời hài lòng với giải pháp nói trên <img src='http://s.wordpress.com/wp-includes/images/smilies/icon_biggrin.gif' alt=':D' class='wp-smiley' /> </p>
<p>Tài liệu tham khảo: <a href="http://www.ryerson.ca/~dgrimsha/courses/cps840/repaint.html">The repaint() method and the GUI thread</a></p>
  <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gocomments/openandfree.wordpress.com/93/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/comments/openandfree.wordpress.com/93/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/godelicious/openandfree.wordpress.com/93/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/delicious/openandfree.wordpress.com/93/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gostumble/openandfree.wordpress.com/93/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/stumble/openandfree.wordpress.com/93/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/godigg/openandfree.wordpress.com/93/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/digg/openandfree.wordpress.com/93/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/goreddit/openandfree.wordpress.com/93/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/reddit/openandfree.wordpress.com/93/" /></a> <img alt="" border="0" src="http://stats.wordpress.com/b.gif?host=openandfree.wordpress.com&blog=1590880&post=93&subd=openandfree&ref=&feed=1" /></div>]]></content:encoded>
			<wfw:commentRss>http://openandfree.wordpress.com/2008/11/22/g%e1%bb%8di-repaint-nhi%e1%bb%81u-l%e1%ba%a7n-trong-jframe-va-japplet/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
	
		<media:content url="http://0.gravatar.com/avatar/0b7240ced9e7e663cff734d741f37158?s=96&#38;d=identicon&#38;r=G" medium="image">
			<media:title type="html">kiennguyen</media:title>
		</media:content>
	</item>
		<item>
		<title>vim plugin for NetBeans</title>
		<link>http://openandfree.wordpress.com/2008/11/20/vim-plugin-for-netbeans/</link>
		<comments>http://openandfree.wordpress.com/2008/11/20/vim-plugin-for-netbeans/#comments</comments>
		<pubDate>Thu, 20 Nov 2008 01:09:34 +0000</pubDate>
		<dc:creator>kiennguyen</dc:creator>
				<category><![CDATA[Java]]></category>
		<category><![CDATA[NetBeans]]></category>
		<category><![CDATA[vim plugin]]></category>

		<guid isPermaLink="false">http://www.openandfree.org/blog/?p=77</guid>
		<description><![CDATA[Khi đã quen viết code trên vi/vim rồi thì chuyển sang editor khác thật khó chịu. Phiền hà nhất là các thao tác di chuyển con trỏ (phải dùng các phím mũi tên lên xuống rất mất thời gian), xóa một từ hoặc một dòng (phải giữ Backspace mỏi cả tay), nhảy giữa các từ&#8230;Tóm [...]<img alt="" border="0" src="http://stats.wordpress.com/b.gif?host=openandfree.wordpress.com&blog=1590880&post=92&subd=openandfree&ref=&feed=1" />]]></description>
			<content:encoded><![CDATA[<div class='snap_preview'><br /><p>Khi đã quen viết code trên vi/vim rồi thì chuyển sang editor khác thật khó chịu. Phiền hà nhất là các thao tác di chuyển con trỏ (phải dùng các phím mũi tên lên xuống rất mất thời gian), xóa một từ hoặc một dòng (phải giữ Backspace mỏi cả tay), nhảy giữa các từ&#8230;Tóm lại với những ai đã quen lập trình trên vi/vim thì việc phải chuyển sang các IDE khác sẽ không khác gì cực hình.</p>
<p>Giải pháp cho vấn đề này là cài đặt vim plugin cho IDE đang sử dụng. Một IDE đang được sử dụng rộng rãi là NetBeans. Để cài đặt vim plugin cho NetBeans, vào link dưới đây để tải về file cài đặt:</p>
<p><a href="http://sourceforge.net/projects/viex/">http://sourceforge.net/projects/viex/</a></p>
<p>Giải nén để nhận được file start-module-myvim.nbm. Từ menu của NetBeans, chọn Tools-&gt;Plugins-&gt;Downloaded-&gt;Add Plugins rồi chọn file start-module-myvim.nbm. Chúng ta sẽ thấy biểu tượng của vim nằm bên cạnh các icon khác như trong hình dưới đây. (Chú ý hình dáng của con trỏ, chúng ta đang ở chế độ lệnh của vim).</p>
<p><img class="alignnone" src="http://farm4.static.flickr.com/3173/3044058495_7b05091433_o.jpg" alt="" width="600" height="400" /></p>
<p>Bây giờ thì chúng ta đã có thể tận hưởng sự tiện lợi trong việc viết code bằng vim kết hợp với những tính năng phức tạp cung cấp bởi NetBeans. Tuy nhiên, plugin này vẫn chưa hỗ trợ một số thao tác edit trong vim như</p>
<p>- Không tự động indent khi xuống dòng bằng phím o.</p>
<p>- Không hỗ trợ shift-o</p>
<p>- Không hỗ trợ ctrl-r (redo).</p>
<p>- Không hỗ trợ xoá nhiều từ liền nhau (d 2 w, d 3 w, d $,&#8230;)</p>
<p>Tuy nhiên với những tính năng hiện có của plugin này thì công việc lập trình trên NetBeans đã trở nên thú vị hơn rất nhiều. Hi vọng những khiếm khuyết nói trên sẽ được khắc phục trong những phiên bản sau.</p>
  <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gocomments/openandfree.wordpress.com/92/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/comments/openandfree.wordpress.com/92/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/godelicious/openandfree.wordpress.com/92/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/delicious/openandfree.wordpress.com/92/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gostumble/openandfree.wordpress.com/92/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/stumble/openandfree.wordpress.com/92/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/godigg/openandfree.wordpress.com/92/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/digg/openandfree.wordpress.com/92/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/goreddit/openandfree.wordpress.com/92/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/reddit/openandfree.wordpress.com/92/" /></a> <img alt="" border="0" src="http://stats.wordpress.com/b.gif?host=openandfree.wordpress.com&blog=1590880&post=92&subd=openandfree&ref=&feed=1" /></div>]]></content:encoded>
			<wfw:commentRss>http://openandfree.wordpress.com/2008/11/20/vim-plugin-for-netbeans/feed/</wfw:commentRss>
		<slash:comments>2</slash:comments>
	
		<media:content url="http://0.gravatar.com/avatar/0b7240ced9e7e663cff734d741f37158?s=96&#38;d=identicon&#38;r=G" medium="image">
			<media:title type="html">kiennguyen</media:title>
		</media:content>

		<media:content url="http://farm4.static.flickr.com/3173/3044058495_7b05091433_o.jpg" medium="image" />
	</item>
		<item>
		<title>Linked List (1) &#8211; Basic</title>
		<link>http://openandfree.wordpress.com/2008/07/26/linked-list-1-basic/</link>
		<comments>http://openandfree.wordpress.com/2008/07/26/linked-list-1-basic/#comments</comments>
		<pubDate>Fri, 25 Jul 2008 18:39:19 +0000</pubDate>
		<dc:creator>Hoang Tran</dc:creator>
				<category><![CDATA[C/C++]]></category>

		<guid isPermaLink="false">http://www.openandfree.org/blog/?p=51</guid>
		<description><![CDATA[Lấy từ tài liệu tuyệt vời này về linked list của trường Stanford mà tôi muốn khái lược lại bằng những đoạn mã trong đó. Danh sách liên kết (linked list) là  một kiến thức rất cơ bản của cấu trúc dữ liệu và giải thuật. Hiểu được những ưu và khuyết điểm của [...]<img alt="" border="0" src="http://stats.wordpress.com/b.gif?host=openandfree.wordpress.com&blog=1590880&post=69&subd=openandfree&ref=&feed=1" />]]></description>
			<content:encoded><![CDATA[<div class='snap_preview'><br /><p style="text-align:justify;">Lấy từ tài liệu tuyệt vời <a href="http://cslibrary.stanford.edu/103/LinkedListBasics.pdf">này</a> về linked list của trường Stanford mà tôi muốn khái lược lại bằng những đoạn mã trong đó. Danh sách liên kết (linked list) là  một kiến thức rất cơ bản của cấu trúc dữ liệu và giải thuật. Hiểu được những ưu và khuyết điểm của nó sẽ giúp chúng ta hiểu các vấn đề về thời gian, không gian bộ nhớ và cấu trúc dữ liệu nói chung. Hơn thế nữa học về linked list là một cách rất tốt để hiểu về pointer. Những bài toán về linked list là sự kết hợp rất &#8220;đẹp&#8221; giữa giải thuật (algorithms) và các phép toán với con trỏ (pointer manipulation). Linked list là cách các lập trình viên luyện tập để thực sự hiểu về pointer và bạn sẽ thấy ngôn ngữ C &#8220;đẹp&#8221; vô cùng <img src='http://s.wordpress.com/wp-includes/images/smilies/icon_smile.gif' alt=':-)' class='wp-smiley' />  Hãy tham khảo thêm tài liệu của Stanford để hiểu kỹ thêm (Highly recommend!)</p>
<p><!--TOC--><br />
<span id="more-69"></span></p>
<h1>Linked list basic</h1>
<h2>Khai báo linked list:</h2>
<pre>struct node {
     int data;
     struct node* next;
};
struct node* head;</pre>
<h2>Hàm length() lấy số phần tử của danh sách</h2>
<pre>
/*
 Given a linked list head pointer, compute
 and return the number of nodes in the list.
*/
int Length(struct node* head) {
    struct node* current = head;
    int count = 0;
    while (current != NULL) {
        count++;
        current = current-&gt;next;
    }
    return count;
}
</pre>
<h2>Duyệt danh sách sử dụng một con trỏ local</h2>
<pre>
struct node* current = head;
while (current != NULL) {
    // do something with *current node
    current = current-&gt;next;
}
</pre>
<h1>Linked List Building</h1>
<h2>3 bước để thêm một node vào đầu linked list</h2>
<li>Cấp phát vùng nhớ cho node mới</li>
<pre>
struct node* newNode;
newNode = malloc(sizeof(struct node));
newNode-&gt;data = data_client_wants_stored;
</pre>
<li>Kết nối trường next của node mới vào đầu danh sách</li>
<pre>
newNode-&gt;next = head;</pre>
<li>Đưa con trỏ head trỏ vào node mới</li>
<pre>
head = newNode;</pre>
<h2>Hàm Push()</h2>
<p style="text-align:justify;">Có vẻ từ 3 bước trên thì việc viết hàm Push() để thêm một node vào đầu danh sách rất dễ dàng. Hãy xem hàm sau và tìm chỗ sai trước khi xem lời giải.</p>
<pre>
void WrongPush(struct node* head, int data) {
     struct node* newNode = malloc(sizeof(struct node));
     newNode-&gt;data = data;
     newNode-&gt;next = head;
     head = newNode;
}
</pre>
<p style="text-align:justify;">Thực ra sai ở dòng</p>
<pre>head = newNode; // NO this line does not work!</pre>
<p style="text-align:justify;">Hãy sửa lại hàm Push() trước khi xem tiếp.</p>
<pre>
/*
Takes a list and a data value.
Creates a new link with the given data and pushes
it onto the front of the list.
The list is not passed in by its head pointer.
Instead the list is passed in as a "reference" pointer
to the head pointer -- this allows us
to modify the caller's memory.
*/
void Push(struct node** headRef, int data) {
     struct node* newNode = malloc(sizeof(struct node));
     newNode-&gt;data = data;
     newNode-&gt;next = *headRef; // The '*' to dereferences back to the real head
     *headRef = newNode;
}
</pre>
<p style="text-align:justify;">Với C++ thì có hỗ trợ truyền tham chiếu (reference &amp;) vào hàm, nên hàm Push có thể viết như sau với C++</p>
<pre>
/*
 Push() in C++ -- we just add a '&amp;' to the right hand
 side of the head parameter type, and the compiler makes
 that parameter work by reference. So this code changes
 the caller's memory, but no extra uses of '*' are necessary --
 we just access "head" directly, and the compiler makes that
 change reference back to the caller.
*/
void Push(struct node*&amp; head, int data) {
     struct node* newNode = malloc(sizeof(struct node));
     newNode-&gt;data = data;
     newNode-&gt;next = head; // No extra use of * necessary on head -- the compiler
     head = newNode; // just takes care of it behind the scenes.
}
</pre>
<h1>Techniques</h1>
<h2>Duyệt xuống (Iterate down)</h2>
<pre>
struct node* current = head;
while (current != NULL) {
     /* Do sth here */
     current = current-&gt;next;
}
</pre>
<p style="text-align:justify;">Có thể thay vòng lặp bằng</p>
<pre>
for (current = head; current != NULL; current = current-&gt;next) {</pre>
<h2>Đổi một pointer bằng một tham chiếu tới pointer (reference pointer)</h2>
<p style="text-align:justify;">Nhiều hàm cần phải thay đổi con trỏ head mặc dù nó được truyền vào hàm số theo kiểu pass-by-value. Để làm điều này trong C thì hãy truyền một pointer đến head pointer thay vì chỉ truyền head pointer. Kiểu pointer chỉ đến một pointer khác thường được gọi là reference pointer.</p>
<p style="text-align:justify;">Hãy xem hàm ChangeToNull để cho con trỏ head trỏ vào NULL</p>
<pre>
// Change the passed in head pointer to be NULL
// Uses a reference pointer to access the caller's memory
void ChangeToNull(struct node** headRef) {
     // Takes a pointer to the value of interest
     *headRef = NULL; // use '*' to access the value of interest
}</pre>
<h2>Build list sử dụng thêm node vào đầu bằng hàm Push</h2>
<p style="text-align:justify;">Phương pháp này làm cho đoạn mã xây dựng list rất ngắn và chạy rất nhanh</p>
<pre>
struct node* AddAtHead() {
	struct node* head = NULL;
	int i;
	for (i=1; i&lt;6; i++) {
		Push(&amp;head, i);
	}
	// head == {5, 4, 3, 2, 1};
	return(head);
}</pre>
<h2>Build list sử dụng con trỏ tail</h2>
<p style="text-align:justify;">Cũng có thể thêm một node mới vào cuối cùng của list. Chúng ta sẽ cần một con trỏ tail trỏ vào node cuối cùng của list và trường next của nó sẽ trỏ vào null. Khi thêm một node mới vào </p>
<pre>
newNode-&gt;next = NULL;
tail-&gt;next = newNode;
tail = tail-&gt;next;</pre>
<p style="text-align:justify;">Tuy nhiên thì có một trường hợp đặc biệt khi phần tử mới thêm vào danh sách là phần tử đầu tiên của list. Hãy xem xét tiếp các kỹ thuật sau.</p>
<h2>Build list sử dụng con trỏ tail có xử lý trường hợp đặc biệt</h2>
<p style="text-align:justify;">Khi build một danh sách bằng cách thêm một node mới vào cuối danh sách thì điểm khó là node đầu tiên phải được thêm vào head pointer và các node khác thì được thêm vào sau node cuối cùng sử dụng tail pointer. Cách đơn giản nhất để xử lý cả điều này là viết hai đoạn code riêng rẽ xử lý chúng. Đầu tiên là đoạn mã thêm vào head pointer cho phần tử đầu tiên và tiếp đó là một vòng lặp sử dụng tail pointer để thêm tất cả các node khác. Trông nó có vẻ &#8220;xấu&#8221; nhưng đơn giản và chạy nhanh.</p>
<pre>
struct node* BuildWithSpecialCase() {
	struct node* head = NULL;
	struct node* tail;
	int i;
	// Deal with the head node here, and set the tail pointer
	Push(&amp;head, 1);
	tail = head;

	// Do all the other nodes using 'tail'
	for (i=2; inext), i); // add node at tail-&gt;next
		tail = tail-&gt;next; // advance tail to point to last node
	}
	return(head); // head == {1, 2, 3, 4, 5};
}</pre>
<h2>Build list sử dụng dummy node</h2>
<p style="text-align:justify;">Một giải pháp khác là sử dụng một dummy node tạm thời ở đầu danh sách. Dummy node sẽ đóng vai trò là phần tử đầu tiên và tất cả các node &#8220;thực sự&#8221; sẽ được thêm vào sau dummy node.</p>
<pre>
struct node* BuildWithDummyNode() {
	struct node dummy; // Dummy node is temporarily the first node
	struct node* tail = &dummy; // Start the tail at the dummy.
	// Build the list on dummy.next (aka tail-&gt;next)
	int i;
	dummy.next = NULL;
	for (i=1; inext), i);
		tail = tail-&gt;next;
	}
	// The real result list is now in dummy.next
	// dummy.next == {1, 2, 3, 4, 5};
	return(dummy.next);
}</pre>
<p style="text-align:justify;">Ở ví dụ trên ta thấy dummy node sẽ không ở trong list khi ra khỏi hàm. Nhưng có một vài cách thể hiện linked list luôn giữ lại dummy node trong suốt quá trình sử dụng nó. Với cách tiếp cận đó thì sẽ không bao giờ có một danh sách rỗng (empty list). Thay vì đó thì danh sách luôn có một dummy node ở đầu. Tuy nhiên thì tôi không khuyến khích phương pháp tiếp cận đó. Phương án sử dụng dummy node tạm thời nên được sử dụng hơn.</p>
<h2>Build list sử dụng tham chiếu cục bộ (local references)</h2>
<p style="text-align:justify;">Cuối cùng đây là một giải pháp rất &#8220;mẹo mực&#8221; mà không phải sự dụng dummy node. Đó là sử dụng một local &#8220;reference pointer&#8221; mà luôn trỏ vào pointer cuối cùng của list chứ không phải node cuối cùng.</p>
<pre>
struct node* BuildWithLocalRef() {
	struct node* head = NULL;
	struct node** lastPtrRef= &head; // Start out pointing to the head pointer
	int i;
	for (i=1; inext); // Advance to point to the
							// new last pointer
	}
	// head == {1, 2, 3, 4, 5};
	return(head);
}</pre>
<p style="text-align:justify;">Kỹ thuật này rất ngắn nhưng bên trong vòng lặp thật &#8220;kinh hoàng&#8221;.</p>
<p style="text-align:justify;">Cả hai giải pháp sử dụng temporary-dummy và reference pointer có hơi chút &#8220;không bình thường&#8221; nhưng nó rất tốt để chắc chắn rằng chúng ta hiểu về pointer bởi vì chúng sử dụng pointer theo cách &#8220;không bình thường&#8221;.</p>
<h1>Các đoạn mã ví dụ</h1>
<h2>AppendNode()</h2>
<pre>
struct node* AppendNode(struct node** headRef, int data) {
	struct node* current = *headRef;
	struct node* newNode;
	newNode = malloc(sizeof(struct node));
	newNode-&gt;data = data;
	newNode-&gt;next = NULL;

	// special case for length 0
	if (current == NULL) {
		*headRef = newNode;
	} else {
		// Locate the last node
		while (current-&gt;next != NULL) {
			current = current-&gt;next;
		}
		current-&gt;next = newNode;
	}
}</pre>
<h2>AppendNode() sử dụng Push()</h2>
<pre>
struct node* AppendNode(struct node** headRef, int data) {
	struct node* current = *headRef;
	// special case for the empty list
	if (current == NULL) {
		Push(headRef, data);
	} else {
		// Locate the last node
		while (current-&gt;next != NULL) {
			current = current-&gt;next;
		}
		// Build the node after the last node
		Push(&amp;(current-&gt;next), data);
	}
}
</pre>
<h2>CopyList()</h2>
<pre>
struct node* CopyList(struct node* head) {
	struct node* current = head; // used to iterate over the original list
	struct node* newList = NULL; // head of the new list
	struct node* tail = NULL; // kept pointing to the last node in the new list
	while (current != NULL) {
		if (newList == NULL) { // special case for the first new node
			newList = malloc(sizeof(struct node));
			newList-&gt;data = current-&gt;data;
			newList-&gt;next = NULL;
			tail = newList;
		} else {
			tail-&gt;next = malloc(sizeof(struct node));
			tail = tail-&gt;next;
			tail-&gt;data = current-&gt;data;
			tail-&gt;next = NULL;
		}
		current = current-&gt;next;
	}
	return(newList);
}</pre>
<h2>CopyList() with Push()</h2>
<pre>
// Variant of CopyList() that uses Push()
struct node* CopyList2(struct node* head) {
	struct node* current = head; // used to iterate over the original list
	struct node* newList = NULL; // head of the new list
	struct node* tail = NULL; // kept pointing to the last node in the new list
	while (current != NULL) {
		if (newList == NULL) { // special case for the first new node
			Push(&amp;newList, current-&gt;data);
			tail = newList;
		} else {
			Push(&amp;(tail-&gt;next), current-&gt;data); // add each node at the tail
			tail = tail-&gt;next; // advance the tail to the new last node
		}
		current = current-&gt;next;
	}
	return(newList);
}</pre>
<h2>CopyList() With Dummy Node</h2>
<pre>
// Dummy node variant
struct node* CopyList(struct node* head) {
	struct node* current = head; // used to iterate over the original list
	struct node* tail; // kept pointing to the last node in the new list
	struct node dummy; // build the new list off this dummy node
	dummy.next = NULL;
	tail = &dummy; // start the tail pointing at the dummy
	while (current != NULL) {
		Push(&amp;(tail-&gt;next), current-&gt;data); // add each node at the tail
		tail = tail-&gt;next; // advance the tail to the new last node
		current = current-&gt;next;
	}
	return(dummy.next);
}</pre>
<h2>CopyList() With Local References</h2>
<pre>
// Local reference variant
struct node* CopyList(struct node* head) {
	struct node* current = head; // used to iterate over the original list
	struct node* newList = NULL;
	struct node** lastPtr;
	lastPtr = &newList; // start off pointing to the head itself
	while (current != NULL) {
		Push(lastPtr, current-&gt;data); // add each node at the lastPtr
		lastPtr = &amp;((*lastPtr)-&gt;next); // advance lastPtr
		current = current-&gt;next;
	}
	return(newList);
}</pre>
<h2>CopyList() Recursive</h2>
<pre>
// Recursive variant
struct node* CopyList(struct node* head) {
	if (head == NULL) return NULL;
	else {
		struct node* newList = malloc(sizeof(struct node)); // make the one node
		newList-&gt;data = current-&gt;data;
		newList-&gt;next = CopyList(current-&gt;next); // recur for the rest
		return(newList);
	}
}</pre>
<h1>Other implementations</h1>
<p style="text-align:justify;">Hãy tham khảo thêm trong tài liệu</p>
<li>Dummy header</li>
<li>Circular</li>
<li>Tail pointer</li>
<li>Head struct</li>
<li>Doubly-linked</li>
<li>Chunk list</li>
<li>Dynamic array</li>
<img alt="" border="0" src="http://feeds.wordpress.com/1.0/categories/openandfree.wordpress.com/69/" /> <img alt="" border="0" src="http://feeds.wordpress.com/1.0/tags/openandfree.wordpress.com/69/" /> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gocomments/openandfree.wordpress.com/69/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/comments/openandfree.wordpress.com/69/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/godelicious/openandfree.wordpress.com/69/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/delicious/openandfree.wordpress.com/69/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gostumble/openandfree.wordpress.com/69/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/stumble/openandfree.wordpress.com/69/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/godigg/openandfree.wordpress.com/69/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/digg/openandfree.wordpress.com/69/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/goreddit/openandfree.wordpress.com/69/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/reddit/openandfree.wordpress.com/69/" /></a> <img alt="" border="0" src="http://stats.wordpress.com/b.gif?host=openandfree.wordpress.com&blog=1590880&post=69&subd=openandfree&ref=&feed=1" /></div>]]></content:encoded>
			<wfw:commentRss>http://openandfree.wordpress.com/2008/07/26/linked-list-1-basic/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
	
		<media:content url="http://1.gravatar.com/avatar/f6f88159a87ae5eb23d369e775bf0e4a?s=96&#38;d=identicon&#38;r=G" medium="image">
			<media:title type="html">hoangtran</media:title>
		</media:content>
	</item>
		<item>
		<title>StringTokenizer</title>
		<link>http://openandfree.wordpress.com/2008/07/21/stringtokenizer/</link>
		<comments>http://openandfree.wordpress.com/2008/07/21/stringtokenizer/#comments</comments>
		<pubDate>Mon, 21 Jul 2008 02:47:14 +0000</pubDate>
		<dc:creator>Hoang Tran</dc:creator>
				<category><![CDATA[C/C++]]></category>

		<guid isPermaLink="false">http://www.openandfree.org/blog/?p=49</guid>
		<description><![CDATA[StringTokenizer là một class thường được viết trong các dự án. Đó là một class dùng để xử lý chuỗi, chia tách chuỗi thành các chuỗi con (token) được phân cách bởi các ký tự định nghĩa trước (delimiter). Ví dụ:
&#8220;Hoang Tran:1982:Hanoi University of Technology&#8221; được phân cách bởi ký tự &#8220;:&#8221; để thu được [...]<img alt="" border="0" src="http://stats.wordpress.com/b.gif?host=openandfree.wordpress.com&blog=1590880&post=65&subd=openandfree&ref=&feed=1" />]]></description>
			<content:encoded><![CDATA[<div class='snap_preview'><br /><p style="text-align:justify;">StringTokenizer là một class thường được viết trong các dự án. Đó là một class dùng để xử lý chuỗi, chia tách chuỗi thành các chuỗi con (token) được phân cách bởi các ký tự định nghĩa trước (delimiter). Ví dụ:</p>
<p style="text-align:justify;">&#8220;Hoang Tran:1982:Hanoi University of Technology&#8221; được phân cách bởi ký tự &#8220;:&#8221; để thu được thông tin tương ứng về tên, năm sinh và trường học.</p>
<p style="text-align:justify;">Có rất nhiều cách thể hiện lớp StringTokenizer này ở các ngôn ngữ khác nhau (Java thì đã có trong JDK của nó rồi) Bạn có thể google để tìm tham khảo các cách viết đó. Dựa trên ý tưởng của java, chúng ta sẽ xây dựng một lớp StringTokenizer hữu dụng trong C++.</p>
<p style="text-align:justify;">Trong nhiều cách viết lớp này ở trên mạng thì mình cũng nhận ra rằng cách viết ở dự án cũ là tối ưu, hay và dễ hiểu nhất <img src='http://s.wordpress.com/wp-includes/images/smilies/icon_smile.gif' alt=':-)' class='wp-smiley' />  Sử dụng deque làm storage data cho lớp StringTokenizer sẽ làm cho quá trình insert cũng như delete các beginning và end của container rất nhanh.</p>
<p style="text-align:justify;">Đây là lớp StringTokenizer đã được thêm bớt chút ít sau khi đi chôm <img src='http://s.wordpress.com/wp-includes/images/smilies/icon_biggrin.gif' alt=':-D' class='wp-smiley' /> </p>
<p><span id="more-65"></span></p>
<pre>
class StringTokenizer
{
  public:
    typedef std::deque::iterator iterator;

    StringTokenizer( std::string str, std::string delim = " \t\r\f\n", bool split = false )
    {
      std::string::size_type pos;
      while (( pos = str.find_first_of( delim ) ) != std::string::npos ) {
        if ( split &amp;&amp; pos == 0 ) {
          _tokens.push_back( std::string() );
        } else if ( pos &gt; 0 ) {
          _tokens.push_back( str.substr( 0, pos ) );
        }
        ++pos;

        /* Skip consecutive delimiter characters when tokenising. */

        if (( ! split ) &amp;&amp; ( ! str.empty() )) {
          for( ; delim.find( str[pos] ) != std::string::npos; ++pos ) {
            /* Empty loop. */
          }
        }
        str = str.substr( pos );
      }

      if (( split ) || ( ! str.empty() )) {
        _tokens.push_back( str );
      }
    }

    StringTokenizer( const StringTokenizer &amp;rhs )
    {
      *this = rhs;
    }

    virtual ~StringTokenizer()
    {
    }

    iterator begin()
    {
      return _tokens.begin();
    }

    iterator end()
    {
      return _tokens.end();
    }

    StringTokenizer&amp; operator=( const StringTokenizer &amp;rhs )
    {
      if ( &amp;rhs != this ) {
        _tokens = rhs._tokens;
      }
      return *this;
    }

    const std::string&amp; operator [] ( int index ) {
      return _tokens[ index ];
    }

    int size() const
    {
      return _tokens.size();
    }
    bool empty() const
    {
      return size() == 0;
    }
    bool has_more_tokens()
    {
      return (_tokens.size() &gt; 0);
    }

    std::string next_token()
    {
      std::string tok = _tokens.front();
      _tokens.pop_front();
      return tok;
    }

  private:
    std::deque _tokens;

};
</pre>
<img alt="" border="0" src="http://feeds.wordpress.com/1.0/categories/openandfree.wordpress.com/65/" /> <img alt="" border="0" src="http://feeds.wordpress.com/1.0/tags/openandfree.wordpress.com/65/" /> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gocomments/openandfree.wordpress.com/65/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/comments/openandfree.wordpress.com/65/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/godelicious/openandfree.wordpress.com/65/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/delicious/openandfree.wordpress.com/65/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gostumble/openandfree.wordpress.com/65/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/stumble/openandfree.wordpress.com/65/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/godigg/openandfree.wordpress.com/65/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/digg/openandfree.wordpress.com/65/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/goreddit/openandfree.wordpress.com/65/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/reddit/openandfree.wordpress.com/65/" /></a> <img alt="" border="0" src="http://stats.wordpress.com/b.gif?host=openandfree.wordpress.com&blog=1590880&post=65&subd=openandfree&ref=&feed=1" /></div>]]></content:encoded>
			<wfw:commentRss>http://openandfree.wordpress.com/2008/07/21/stringtokenizer/feed/</wfw:commentRss>
		<slash:comments>2</slash:comments>
	
		<media:content url="http://1.gravatar.com/avatar/f6f88159a87ae5eb23d369e775bf0e4a?s=96&#38;d=identicon&#38;r=G" medium="image">
			<media:title type="html">hoangtran</media:title>
		</media:content>
	</item>
		<item>
		<title>[Basic] Pointer</title>
		<link>http://openandfree.wordpress.com/2008/04/02/basic-pointer/</link>
		<comments>http://openandfree.wordpress.com/2008/04/02/basic-pointer/#comments</comments>
		<pubDate>Wed, 02 Apr 2008 15:47:07 +0000</pubDate>
		<dc:creator>Hoang Tran</dc:creator>
				<category><![CDATA[C/C++]]></category>

		<guid isPermaLink="false">http://www.openandfree.org/blog/?p=46</guid>
		<description><![CDATA[Phần này sẽ khái lược rất nhanh một vài điểm về các quy tắc sử dụng con trỏ. Để tham khảo toàn diện về con trỏ và bộ nhớ hãy xem tài liệu Pointers and Memory http://cslibrary.stanford.edu/102/).
-         Pointer/Pointee: Một con trỏ “pointer” sẽ lưu một reference đến [...]<img alt="" border="0" src="http://stats.wordpress.com/b.gif?host=openandfree.wordpress.com&blog=1590880&post=51&subd=openandfree&ref=&feed=1" />]]></description>
			<content:encoded><![CDATA[<div class='snap_preview'><br /><p class="MsoNormal" style="text-align:justify;"><span style="font-size:10pt;font-family:Verdana;">Phần này sẽ khái lược rất nhanh một vài điểm về các quy tắc sử dụng con trỏ. Để tham khảo toàn diện về con trỏ và bộ nhớ hãy xem tài liệu Pointers and Memory <a href="http://cslibrary.stanford.edu/102/">http://cslibrary.stanford.edu/102/</a>).</span></p>
<p class="MsoNormal" style="margin-left:0.5in;text-align:justify;text-indent:-0.25in;"><!--[if !supportLists]--><span style="font-size:10pt;font-family:Verdana;"><span>-<span style="font-family:'Times New Roman';font-style:normal;font-variant:normal;font-weight:normal;font-size:7pt;line-height:normal;">         </span></span></span><!--[endif]--><span style="font-size:10pt;font-family:Verdana;">Pointer/Pointee: Một con trỏ “pointer” sẽ lưu một reference đến một biến khác được biết như là pointee của nó. Con trỏ có thể được thiết lập giá trị NULL có nghĩa là nó refer đến một pointee nào. (Trong C và C++, giá trị NULL có thể được sử dụng như là giá trị boolean false).</span></p>
<p class="MsoNormal" style="margin-left:0.5in;text-align:justify;text-indent:-0.25in;"><!--[if !supportLists]--><span style="font-size:10pt;font-family:Verdana;"><span>-<span style="font-family:'Times New Roman';font-style:normal;font-variant:normal;font-weight:normal;font-size:7pt;line-height:normal;">         </span></span></span><!--[endif]--><span style="font-size:10pt;font-family:Verdana;">Dereference: Toán tử dereference trên con trỏ cho phép truy nhập vào pointee của nó. Một pointer chỉ có thể bị dereference sau khi nó được thiết lập trỏ đến một pointee cụ thể. Một pointer mà không có pointee thì là bad pointer và không thể bị dereference. </span></p>
<p class="MsoNormal" style="margin-left:0.5in;text-align:justify;text-indent:-0.25in;"><!--[if !supportLists]--><span style="font-size:10pt;font-family:Verdana;"><span>-<span style="font-family:'Times New Roman';font-style:normal;font-variant:normal;font-weight:normal;font-size:7pt;line-height:normal;">         </span></span></span><!--[endif]--><span style="font-size:10pt;font-family:Verdana;">Bad pointer: Một pointer mà không được trỏ vào một pointee thì là “bad” và không thể dereference. Trong C và C++, việc dereference một bad pointer đôi khi gây xung đột ngay lập tức và làm hỏng bộ nhớ của chương trình đang chạy, gây nên &#8220;không biết đường nào mà lần&#8221;. Kiểu lỗi này rất khó để theo dõi. Trong C và C++, tất cả các pointer bắt đầu bằng bad values (những giá trị ngẫu nhiên), do đó rất dễ tình cờ sử dụng bad pointer. Những đoạn mã đúng sẽ thiết lập mỗi pointer có một good value trước khi sử dụng chúng. Chính vì vậy sử dụng bad pointer là một lỗi rất phổ biến trong C/C++. Với Java và các ngôn ngữ khác, các pointers được tự động bắt đầu với giá trị NULL, do đó quá trình dereference sẽ được dễ dàng detect nên các chương trình Java dễ gỡ lỗi này hơn nhiều. </span></p>
<p class="MsoNormal" style="margin-left:0.5in;text-align:justify;text-indent:-0.25in;"><!--[if !supportLists]--><span style="font-size:10pt;font-family:Verdana;"><span>-<span style="font-family:'Times New Roman';font-style:normal;font-variant:normal;font-weight:normal;font-size:7pt;line-height:normal;">         </span></span></span><!--[endif]--><span style="font-size:10pt;font-family:Verdana;">Pointer assignment: Một phép gán giữa hai con trỏ như p = q; sẽ làm cho hai pointer trỏ vào cùng một pointee. Nó sẽ không copy vùng nhớ của pointee. Sau phép gán thì cả hai pointer sẽ chỉ vào cùng một vùng nhớ của pointee. </span></p>
<p class="MsoNormal" style="margin-left:0.5in;text-align:justify;text-indent:-0.25in;"><!--[if !supportLists]--><span style="font-size:10pt;font-family:Verdana;"><span>-<span style="font-family:'Times New Roman';font-style:normal;font-variant:normal;font-weight:normal;font-size:7pt;line-height:normal;">         </span></span></span><!--[endif]--><span style="font-size:10pt;font-family:Verdana;">malloc(): malloc() là một hàm hệ thống mà cấp pháp một vùng nhớ trong “heap” và trả về con trỏ tới vùng nhớ mới đó. Prototype của malloc() và các hàm khác ở trong stdlib.h. Tham số của malloc() là một số nguyên là kích thước của vùng nhớ cần cấp phát tính theo bytes. Không giống như các biến cục bộ (“stack”), vùng nhớ heap không tự động giải phóng khi hàm tạo thoát ra. malloc() sẽ trả về NULL nếu nó không thế đáp ứng được yêu cầu cấp phát. Bạn nên kiểm tra trường hợp NULL với assert() nếu bạn mong nó an toàn. Hầu hết các hệ điều hành tiên tiến sẽ ném ra một exception hoặc làm việc bắt lỗi tự động trong việc cấp phát bộ nhớ của chúng, do đó không nhất thiết là trong đoạn mã của bạn phải kiểm tra việc cấp phát bộ nhớ thất bại. </span></p>
<p class="MsoNormal" style="margin-left:0.5in;text-align:justify;text-indent:-0.25in;"><!--[if !supportLists]--><span style="font-size:10pt;font-family:Verdana;"><span>-<span style="font-family:'Times New Roman';font-style:normal;font-variant:normal;font-weight:normal;font-size:7pt;line-height:normal;">         </span></span></span><!--[endif]--><span style="font-size:10pt;font-family:Verdana;">free(): free() thì ngược với malloc(). Gọi hàm free() trên vùng nhớ trên heap để chỉ ra rằng hệ thống đã thực hiện xong và giải phóng vùng nhớ đó. Tham số của free là một con trỏ tới vùng nhớ trên heap – con trỏ mà chúng ta đã có được thông qua lời gọi tới hàm malloc().</span></p>
<p class="MsoNormal" style="text-align:center;"><span style="text-align:center; display: block;"><a href="http://openandfree.wordpress.com/2008/04/02/basic-pointer/"><img src="http://img.youtube.com/vi/f-pJlnpkLp0/2.jpg" alt="" /></a></span></p>
<img alt="" border="0" src="http://feeds.wordpress.com/1.0/categories/openandfree.wordpress.com/51/" /> <img alt="" border="0" src="http://feeds.wordpress.com/1.0/tags/openandfree.wordpress.com/51/" /> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gocomments/openandfree.wordpress.com/51/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/comments/openandfree.wordpress.com/51/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/godelicious/openandfree.wordpress.com/51/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/delicious/openandfree.wordpress.com/51/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gostumble/openandfree.wordpress.com/51/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/stumble/openandfree.wordpress.com/51/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/godigg/openandfree.wordpress.com/51/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/digg/openandfree.wordpress.com/51/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/goreddit/openandfree.wordpress.com/51/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/reddit/openandfree.wordpress.com/51/" /></a> <img alt="" border="0" src="http://stats.wordpress.com/b.gif?host=openandfree.wordpress.com&blog=1590880&post=51&subd=openandfree&ref=&feed=1" /></div>]]></content:encoded>
			<wfw:commentRss>http://openandfree.wordpress.com/2008/04/02/basic-pointer/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
	
		<media:content url="http://1.gravatar.com/avatar/f6f88159a87ae5eb23d369e775bf0e4a?s=96&#38;d=identicon&#38;r=G" medium="image">
			<media:title type="html">hoangtran</media:title>
		</media:content>

		<media:content url="http://img.youtube.com/vi/f-pJlnpkLp0/2.jpg" medium="image" />
	</item>
		<item>
		<title>Các kiểu khởi tạo biến</title>
		<link>http://openandfree.wordpress.com/2008/02/23/cac-ki%e1%bb%83u-kh%e1%bb%9fi-t%e1%ba%a1o-bi%e1%ba%bfn/</link>
		<comments>http://openandfree.wordpress.com/2008/02/23/cac-ki%e1%bb%83u-kh%e1%bb%9fi-t%e1%ba%a1o-bi%e1%ba%bfn/#comments</comments>
		<pubDate>Sat, 23 Feb 2008 07:48:43 +0000</pubDate>
		<dc:creator>kiennguyen</dc:creator>
				<category><![CDATA[C/C++]]></category>
		<category><![CDATA[constructor]]></category>
		<category><![CDATA[initialization]]></category>

		<guid isPermaLink="false">http://www.openandfree.org/blog/?p=44</guid>
		<description><![CDATA[Một bài viết nhỏ để warm-up cái blog sau những ngày đông giá lạnh  
Nguồn: http://www.gotw.ca/gotw/001.htm
Câu hỏi: Cho biết sự khác nhau của những dòng khởi tạo biến sau đây

SomeType t;
SomeType t();
SomeType t( u );
SomeType t = u;
Trả lời:

SomeType t;
Biến t được khởi tạo bởi default constructor SomeType::SomeType()

SomeType t();
Một dòng lệnh dễ gây nhầm [...]<img alt="" border="0" src="http://stats.wordpress.com/b.gif?host=openandfree.wordpress.com&blog=1590880&post=49&subd=openandfree&ref=&feed=1" />]]></description>
			<content:encoded><![CDATA[<div class='snap_preview'><br /><p align="justify">Một bài viết nhỏ để warm-up cái blog sau những ngày đông giá lạnh <img src='http://s.wordpress.com/wp-includes/images/smilies/icon_biggrin.gif' alt=':-D' class='wp-smiley' /> </p>
<p align="justify">Nguồn: <a href="http://www.gotw.ca/gotw/001.htm">http://www.gotw.ca/gotw/001.htm</a></p>
<p align="justify"><strong>Câu hỏi</strong>: Cho biết sự khác nhau của những dòng khởi tạo biến sau đây</p>
<pre>
SomeType t;
SomeType t();
SomeType t( u );
SomeType t = u;</pre>
<p align="justify"><strong>Trả lời</strong>:</p>
<pre>
SomeType t;</pre>
<p align="justify">Biến t được khởi tạo bởi default constructor SomeType::SomeType()</p>
<pre>
SomeType t();</pre>
<p align="justify">Một dòng lệnh dễ gây nhầm lẫn! Thực ra đây là dòng khai báo một HÀM không có tham số và trả về một giá trị kiểu SomeType.</p>
<pre>
SomeType t( u );</pre>
<p align="justify">Đây là dòng lệnh khởi tạo biến trực tiếp (direct initialization). Biến t được khởi tạo nhờ constructor SomeType::SomeType( u );</p>
<pre>
SomeType t = u;</pre>
<p align="justify">Nhiều người nhầm lẫn rằng lệnh này gọi đến toán tử gán (assignment operator). Thực ra đây là một khởi tạo sao chép, trong đó t được khởi tạo nhờ copy constructor của lớp SomeType. Nếu u không thuộc kiểu SomeType thì constructor SomeType::SomeType( u ) sẽ được gọi để tạo ra một đối tượng tạm thời kiểu SomeType từ u, sau đó đối tượng này sẽ được sao chép sang t bởi copy constructor.</p>
<p><span id="more-49"></span></p>
<p align="justify">Chúng ta có thể dễ dàng kiểm chứng sự khác nhau nói trên nhờ đoạn mã sau đây:</p>
<pre>
#include 

class SomeType
{
  pubic:
    //Default constructor
    SomeType() {
      std::cout  &lt;&lt; “Default constructor called” &lt;&lt; std::endl;
    }

    //Another constructor
    SomeType( AnotherType u ) {
      std::cout &lt;&lt; “Another constructor called” &lt;&lt; std::endl;
    }

    //Copy constructor
    SomeType( const SomeType &amp;rhs ) {
      std::cout &lt;&lt; “Copy constructor called” &lt;&lt; std::endl;
    }

    //Assignment operator
    SomeType&amp; operator=( const SomeType &amp;rhs ) {
      std::cout &lt;&lt; “Assignment operator called” &lt;&lt; std::endl;
    }

};

int main()
{
  SomeType t;
 //SomeType t();
 //SomeType t( u );
 //SomeType t = u;
 return EXIT_SUCCESS;
}</pre>
<p align="justify"><strong>Chú ý</strong>: Một số dự án khuyến khích nhân viên sử dụng kiểu khởi tạo SomeType t = u để tránh nhầm lẫn với các khai báo hàm.</p>
<img alt="" border="0" src="http://feeds.wordpress.com/1.0/categories/openandfree.wordpress.com/49/" /> <img alt="" border="0" src="http://feeds.wordpress.com/1.0/tags/openandfree.wordpress.com/49/" /> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gocomments/openandfree.wordpress.com/49/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/comments/openandfree.wordpress.com/49/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/godelicious/openandfree.wordpress.com/49/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/delicious/openandfree.wordpress.com/49/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gostumble/openandfree.wordpress.com/49/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/stumble/openandfree.wordpress.com/49/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/godigg/openandfree.wordpress.com/49/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/digg/openandfree.wordpress.com/49/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/goreddit/openandfree.wordpress.com/49/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/reddit/openandfree.wordpress.com/49/" /></a> <img alt="" border="0" src="http://stats.wordpress.com/b.gif?host=openandfree.wordpress.com&blog=1590880&post=49&subd=openandfree&ref=&feed=1" /></div>]]></content:encoded>
			<wfw:commentRss>http://openandfree.wordpress.com/2008/02/23/cac-ki%e1%bb%83u-kh%e1%bb%9fi-t%e1%ba%a1o-bi%e1%ba%bfn/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
	
		<media:content url="http://0.gravatar.com/avatar/0b7240ced9e7e663cff734d741f37158?s=96&#38;d=identicon&#38;r=G" medium="image">
			<media:title type="html">kiennguyen</media:title>
		</media:content>
	</item>
		<item>
		<title>Unix programming with standard I/O (2)</title>
		<link>http://openandfree.wordpress.com/2008/01/22/unix-programming-with-standard-io-2/</link>
		<comments>http://openandfree.wordpress.com/2008/01/22/unix-programming-with-standard-io-2/#comments</comments>
		<pubDate>Tue, 22 Jan 2008 12:46:22 +0000</pubDate>
		<dc:creator>kiennguyen</dc:creator>
				<category><![CDATA[C/C++]]></category>
		<category><![CDATA[Unix/Linux/BSD]]></category>
		<category><![CDATA[cat]]></category>
		<category><![CDATA[standard I/O]]></category>
		<category><![CDATA[system]]></category>
		<category><![CDATA[terminal]]></category>
		<category><![CDATA[unix programming]]></category>

		<guid isPermaLink="false">http://www.openandfree.org/blog/?p=43</guid>
		<description><![CDATA[Phần 2: Chương trình hiển thị nội dung file theo từng trang màn hình
1.	Đặt vấn đề
 Khi xem nội dung một file dài, chúng ta thường muốn nội dung file đó được hiển thị lần lượt theo từng trang màn hình. Hai lệnh phổ biến để xem nội dung file là cat và more không [...]<img alt="" border="0" src="http://stats.wordpress.com/b.gif?host=openandfree.wordpress.com&blog=1590880&post=48&subd=openandfree&ref=&feed=1" />]]></description>
			<content:encoded><![CDATA[<div class='snap_preview'><br /><h3>Phần 2: Chương trình hiển thị nội dung file theo từng trang màn hình</h3>
<p align="justify"><strong>1.	Đặt vấn đề</strong></p>
<p align="justify"> Khi xem nội dung một file dài, chúng ta thường muốn nội dung file đó được hiển thị lần lượt theo từng trang màn hình. Hai lệnh phổ biến để xem nội dung file là cat và more không đáp ứng được nhu cầu này (chúng không có khả năng này, hoặc có nhưng không tiện dụng, “tác giả” cũng không biết rõ về tất cả các khả năng của hai lệnh này). Bởi vậy, chúng ta sẽ phát triển một chương trình tên là p làm nhiệm vụ in ra nội dung một file theo từng trang màn hình (screenful-at-a-time). Chương trình sẽ đợi người dùng ấn một phím để chuyển sang hiển thị trang tiếp theo. Giống như vis, p nhận dữ liệu vào từ cả file lẫn standard input. Ví dụ:</p>
<p align="justify">p nhận dữ liệu vào từ file</p>
<pre>
$ p vis.c</pre>
<p align="justify">p nhận dữ liệu vào từ standard input</p>
<pre>
$ grep  ‘#define’  *.[ch]  |  p</pre>
<p align="justify">Ở phiên bản đầu tiên, p sẽ hiển thị nội dung file theo từng khối, mỗi khối 22 dòng (phần lớn các terminal gồm 24 dòng văn bản). Một cách đơn giản để nhắc người dùng ấn một phím để tiếp tục là không in ra kí tự new line nằm cuối dòng thứ 22. Khi đó, con trỏ sẽ nằm ở cuối dòng thứ 22 thay vì đầu dòng thứ 23. Khi người dùng ấn phím enter, kí tự new line còn thiếu của dòng 22 sẽ được thêm vào, nhờ đó dòng tiếp theo (dòng 23) sẽ được in ra ở đúng vị trí của nó. Nếu người dùng ấn ctrl-d hay q thay vì enter, p sẽ kết thúc. Chúng ta sẽ không quan tâm đến các dòng quá dài. Ngoài ra, khi hiển thị nhiều file cùng lúc thì nội dung các file sẽ được in ra liên tục mà không có sự phân cách gì cả. Tức là, đầu ra của hai lệnh sau đây là như nhau</p>
<pre>$ p file1 file2 …</pre>
<p align="justify">và</p>
<pre>$ cat file1 file2 …  |  p</pre>
<p align="justify">Chú ý rằng lệnh cat in ra nội dung các file một cách liên tục mà không có sự phân cách gì cả. Nếu muốn nội dung các file được phân cách bởi tên file, chúng ta có thể dùng vòng lặp sau đây (ôn lại lập trình shell luôn <img src='http://s.wordpress.com/wp-includes/images/smilies/icon_biggrin.gif' alt=':-D' class='wp-smiley' /> )</p>
<pre>$ for i in filenames
&gt; do
&gt;      echo $i:
&gt;      cat $i
&gt; done  |  p</pre>
<p align="justify">Có rất nhiều tính năng có thể được đưa vào chương trình p. Quan điểm của chúng ta là: <strong>Trước hết tạo ra một phiên bản đơn giản, sau đó dần dần thêm vào các tính năng phức tạp hơn khi cần thiết. Những tính năng được thêm vào phải là những cái mà người dùng thực sự muốn, chứ không phải những cái mà chúng ta nghĩ rằng họ muốn</strong>.</p>
<p align="justify"><strong>2. Phiên bản đầu tiên của p</strong></p>
<p align="justify">Cấu trúc của p cũng tương tự như vis: Hàm main duyệt qua các file đầu vào và gọi một hàm tên là print để xử lí từng file. Dưới đây là hàm main</p>
<p><span id="more-48"></span></p>
<pre>
/* p: print input in chunks (version 1) */

#include 

#define PAGESIZE 22

char *progname; /* program name for error message */

main( int argc, char *argv[ ] )

{

  int i;

  FILE *fp, *efopen( char*, char* );

  void print( FILE*, int );

  progname = argv[ 0 ];

  if( argc == 1 )

    print( stdin, PAGESIZE );

  else

    for( i = 1; i &lt; argc; i++ ) {

      fp = efopen( argv[ i ], “r” );

      print( fp, PAGESIZE );

      fclose( fp );

    }

  exit( 0 );

}</pre>
<p align="justify">Hàm efopen đóng gói các xử lí quen thuộc: Mở một file, nếu không thành công thì in ra thông báo lỗi và dừng chương trình. Thông báo lỗi bao gồm tên chương trình chứa trong một biến external tên là progname được khởi tạo giá trị trong hàm main.</p>
<pre>
/* open file, die if cannot */

FILE *efopen( char *file, char *mode )

{

  FILE *fp;

  extern char *progname;

  if( ( fp = fopen( file, “r” ) ) != NULL )

    return fp;

  fprintf( stderr, “%s: cannot open file %s mode %s\n”, progname, file, mode );

  exit( 1 );

}</pre>
<p align="justify">Có nhiều phương án khác để thiết kế hàm efopen. Cách thứ nhất là khi gặp lỗi mở file, chúng ta in ra thông báo lỗi và trả về con trỏ NULL. Phương án này cho phép người dùng tự quyết định có tiếp tục xử lí hay dừng chương trình. Cách thứ hai là đưa vào một tham số thứ ba cho efopen, chỉ định hàm sẽ dừng chương trình hay trả về NULL trong trường hợp không thể mở file. Trong ngữ cảnh cụ thể của chương trình p, không có lí do gì để chương trình tiếp tục chạy khi không thể mở một file đầu vào. Bởi vậy, thiết kế hiện thời của hàm print là chấp nhận được. Phần xử lí quan trọng nhất của p được thực hiện bởi hàm print.</p>
<pre>
/* print fp in pagesize chunks */

void print( FILE *fp, int pagesize )

{

  char ttyin();

  static int lines = 0; /* Số dòng đã được in ra trên một trang màn hình */

  char buf[ BUFSIZ ];

  while( fgets( buf, sizeof buf, fp ) != NULL ) {

  if( ++lines &lt; pagesize ) {

      fputs( buf, stdout );

    } else {

      buf[ strlen( buf ) – 1 ] = ‘’;

      fputs( buf, stdout );

      fflush( stdout );

      ttyin();

      lines = 0;

    }

  }

}</pre>
<p align="justify">BUFSIZ là một hằng số được định nghĩa trong stdio.h. Hàm fgets( buf, size, fp ) đọc dòng văn bản tiếp theo từ fp vào buf và thêm kí tự ‘’ vào cuối  dòng đó. Dòng được đọc bao gồm cả kí tự new line ở cuối. Ngoài ra, độ dài của nó không được vượt quá size – 1 kí tự. <strong>Thiết kế của hàm fgets có hai điểm chưa tốt. Thứ nhất, nó nên trả về số kí tự vừa được đọc thay vì giá trị buf. Thứ hai, nó không hề đưa ra cảnh báo khi phải xử lí một dòng văn bản dài quá size – 1 kí tự. Mặc dù không có kí tự nào bị mất, chúng ta sẽ phải kiểm tra nội dung của buf để biết thực sự fgets xử lí các dòng quá dài như thế nào!!!</strong> Hàm strlen trả về độ dài của xâu, không tính kí tự ‘’ ở cuối. <strong>Hãy chú ý cách sử dụng strlen để loại bỏ kí tự cuối cùng khỏi một xâu</strong>, trong trường hợp này là kí tự new line. Việc đọc vào phím được ấn được thực hiện bởi hàm ttyin. Hàm ttyin bắt buộc phải đọc dữ liệu từ bàn phím (/dev/tty) chứ không phải từ standard input để đề phòng trường hợp standard input bị định hướng lại thành một file hay một pipeline. Chúng ta thiết kế hàm ttyin sao cho nó trả về kí tự đầu tiên trong chuỗi các kí tự được ấn bởi người dùng, tuy nhiên giá trị này chưa được sử dụng trong phiên bản đầu tiên của p.</p>
<pre>
/* process response from /dev/tty (version 1) */

char ttyin()

{

  char buf[ BUFSIZ ];

  FILE *efopen( char*, char* );

  static FILE *tty = NULL;

  if( tty == NULL )

    tty = efopen( “/dev/tty”, “r” );

  if( ( fgets( buf, BUFSIZ, tty ) == NULL ) || ( buf[ 0 ] == ‘q’ ) )

    exit( 0 );

  else

    return buf[ 0 ];

}</pre>
<p align="justify"><strong>3. Phát triển chương trình</strong></p>
<p align="justify">Phiên bản thứ nhất của p làm duy nhất một việc: In ra nội dung file theo từng trang 22 dòng và đợi phản ứng từ người dùng. Có rất nhiều tính năng mới có thể được thêm vào p mà không đòi hỏi nhiều công sức. Tuy nhiên, thực tế cho thấy những tính năng đó hiếm khi được sử dụng!!! Sự mở rộng đơn giản đầu tiên của p là cho phép người dùng nhập vào số dòng của file sẽ được in ra trên một trang màn hình. Lệnh sau đây</p>
<pre>$ p –n file</pre>
<p align="justify">sẽ in ra nội dung của file theo từng trang, mỗi trang n dòng. Tương tự như chương trình vis, chúng ta thêm đoạn mã sau đây vào hàm main.</p>
<pre>
/* p: print input in chunks (version 2) */

…

progname = argv[ 0 ];

if( ( argc &gt; 1 ) &amp;&amp; ( argv[ 1 ][ 0 ] == ‘-‘ ) ) {

  pagesize = atoi( &amp;argv[ 1 ][ 1 ] );

  argc--;

  argv++;

}

if( argc == 1 )

…</pre>
<p align="justify">Một tính năng mở rộng nữa của p là tạm thời dừng hiển thị nội dung file để thực thi các lệnh khác. <strong>Giống như trong ed và nhiều chương trình khác của Unix, khi người dùng gõ vào một dòng văn bản bắt đầu bởi dấu chấm than (exclaimation mark) thì phần còn lại của dòng đó sẽ được coi như một câu lệnh và sẽ được chuyển tới shell để thực hiện</strong>. Tính năng này được cài đặt khá đơn giản nhờ hàm system. Chúng ta có phiên bản mới của hàm ttyin như sau.</p>
<pre>
/* process response from /dev/tty (version 2) */

char ttyin()

{

  char buf[ BUFSIZ ];

  FILE *efopen( char*, char* );

  static FILE *tty = NULL;

  if( tty == NULL )

    tty = efopen( “/dev/tty”, “r” );

  for( ; ; ) {

    if( ( fgets( buf, BUFSIZ, fp ) == NULL ) || ( buf[ 0 ] == ‘q’ ) ) {

      exit( 0 );

    } else if( buf[ 0 ] == ‘!’ ) {

      system( buf + 1 ); /* BUG here!!! */

      printf( “!\n” );

    } else {

      return buf[ 0 ];

    }

  }

}</pre>
<p align="justify">Tuy nhiên, phiên bản này của ttyin có mỗi lỗi rất tinh vi. <strong>Các lệnh chạy bởi hàm system kế thừa standard input từ p</strong>. Khi p đọc dữ liệu vào từ một pineline hay một file, do standard input bị định hướng lại,  thì lệnh chạy bởi system cũng sẽ nhận dữ liệu từ chính standard input đó chứ không nhận từ người dùng thông qua terminal nữa. Trong trường hợp dưới đây, khi người dùng nhập vào dòng văn bản !ed, nhẽ ra chương trình ed sẽ được gọi và sẽ chờ người dùng nhập dữ liệu vào từ bàn phím. Tuy nhiên do standard input đã bị định hướng lại sang pinepline nên ed lại đọc dữ liệu từ chính file /etc/passwd và sau đó kết thúc ngay lập tức.</p>
<pre>$ cat /etc/passwd | p -1

root:3D.fHR5KoB.3s:0:1:S.User:/:!ed

?

!</pre>
<p align="justify">Lỗi này sẽ được giải quyết trong phần sau. Ở thời điểm này chúng ta chỉ cần nhớ rằng <strong>sử dụng hàm system có thể gây ra lỗi</strong>.</p>
<p align="justify">Chúng ta vừa phát triển hai chương trình vis và p, có thể coi là các biến thể của lệnh cat. Liệu hai chương trình này có nên được tích hợp vào cat dưới dạng các tham số tùy chọn –v và –p hay không? <strong>Chúng ta thường xuyên phải đứng trước hai sự lựa chọn: Viết một chương trình hoàn toàn mới hay thêm tính năng vào một chương trình cũ? Nguyên tắc cơ bản ở đây là: Mỗi chương trình chỉ nên làm một công việc cụ thể mà thôi</strong>. Một chương trình làm quá nhiều việc sẽ rất cồng kềnh, chạy chậm, khó bảo trì và khó sử dụng. Rất nhiều tính năng không được sử dụng đến bởi người dùng không thể nhớ được chúng!!! Chúng ta không nên nhập vis và cat vào làm một. cat thuần túy sao chép dữ liệu từ “input” sang “output” mà không xử lí gì cả. Trong khi đó, vis thực hiện chuyển đổi (transform) từ “input” sang “output”. Nhập vis và cat làm một sẽ tạo ra một chương trình làm hai việc khác nhau. Chúng ta cũng không nên gộp p và cat làm một. cat được dùng để in dữ liệu văn bản nhanh và hiệu quả. Trong khi đó, p được dùng để “duyệt” (browse) dữ liệu văn bản theo cách tiện lợi nhất đối với người dùng. Để ba chương trình cat, vis và p tồn tại riêng rẽ là một quyết định thiết kế hợp lí.</p>
<p align="justify"><strong>4. Một số hướng phát triển chương trình</strong></p>
<p>- p sẽ chạy như thế nào nếu giá trị pagesize nhỏ hơn 0?<br />
- Những tính năng nào có thể được thêm vào p? Bổ sung khả năng tìm kiếm một dòng theo vị trí hay nội dung theo cả hai chiều xuôi (fordward) và ngược (backward). Bổ sung khả năng in ra nội dung file theo từng khối nhỏ hơn pagesize.<br />
- Sử dụng hàm exec để sửa lỗi gây ra bởi hàm system.<br />
- Phiên bản hiện thời của p sẽ “im lặng” đợi người dùng nhập dữ liệu vào từ bàn phím. Sử dụng hàm isatty để khắc phục nhược điểm này.</p>
<p align="justify"><strong>Phần tiếp theo: Chương trình lựa chọn tham số PICK và chương trình chấm dứt các tiến trình ZAP</strong></p>
<img alt="" border="0" src="http://feeds.wordpress.com/1.0/categories/openandfree.wordpress.com/48/" /> <img alt="" border="0" src="http://feeds.wordpress.com/1.0/tags/openandfree.wordpress.com/48/" /> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gocomments/openandfree.wordpress.com/48/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/comments/openandfree.wordpress.com/48/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/godelicious/openandfree.wordpress.com/48/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/delicious/openandfree.wordpress.com/48/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gostumble/openandfree.wordpress.com/48/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/stumble/openandfree.wordpress.com/48/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/godigg/openandfree.wordpress.com/48/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/digg/openandfree.wordpress.com/48/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/goreddit/openandfree.wordpress.com/48/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/reddit/openandfree.wordpress.com/48/" /></a> <img alt="" border="0" src="http://stats.wordpress.com/b.gif?host=openandfree.wordpress.com&blog=1590880&post=48&subd=openandfree&ref=&feed=1" /></div>]]></content:encoded>
			<wfw:commentRss>http://openandfree.wordpress.com/2008/01/22/unix-programming-with-standard-io-2/feed/</wfw:commentRss>
		<slash:comments>7</slash:comments>
	
		<media:content url="http://0.gravatar.com/avatar/0b7240ced9e7e663cff734d741f37158?s=96&#38;d=identicon&#38;r=G" medium="image">
			<media:title type="html">kiennguyen</media:title>
		</media:content>
	</item>
		<item>
		<title>Unix programming with standard I/O (1)</title>
		<link>http://openandfree.wordpress.com/2008/01/17/unix-programming-with-standard-io/</link>
		<comments>http://openandfree.wordpress.com/2008/01/17/unix-programming-with-standard-io/#comments</comments>
		<pubDate>Thu, 17 Jan 2008 10:49:20 +0000</pubDate>
		<dc:creator>kiennguyen</dc:creator>
				<category><![CDATA[C/C++]]></category>
		<category><![CDATA[Unix/Linux/BSD]]></category>
		<category><![CDATA[standard I/O]]></category>
		<category><![CDATA[unix programming]]></category>

		<guid isPermaLink="false">http://www.openandfree.org/blog/?p=42</guid>
		<description><![CDATA[Lời tựa
Dạo này đang thời kì nông nhàn nên quay lại với blog. Gần một tháng nay không có bài viết mới nào, có lẽ do các blogger đều đang bận bịu với những kế hoạch riêng của mình. Dạo này không thích những thứ loằng ngoằng phức tạp nữa, cũng chả thích mình là [...]<img alt="" border="0" src="http://stats.wordpress.com/b.gif?host=openandfree.wordpress.com&blog=1590880&post=47&subd=openandfree&ref=&feed=1" />]]></description>
			<content:encoded><![CDATA[<div class='snap_preview'><br /><p align="justify"><strong>Lời tựa</strong></p>
<p align="justify">Dạo này đang thời kì nông nhàn nên quay lại với blog. Gần một tháng nay không có bài viết mới nào, có lẽ do các blogger đều đang bận bịu với những kế hoạch riêng của mình. Dạo này không thích những thứ loằng ngoằng phức tạp nữa, cũng chả thích mình là guru nữa, đau đầu lắm <img src='http://s.wordpress.com/wp-includes/images/smilies/icon_biggrin.gif' alt=':-D' class='wp-smiley' /> . Bây giờ chỉ thích những thứ đơn giản nhưng đẹp đẽ. Ngẫm ra làm phần mềm cũng chẳng cần đến những thứ cao siêu hay phức tạp, vấn đề chỉ là kết hợp những thứ thật đơn giản thành một hệ thống lớn làm việc được mà thôi.</p>
<p align="justify">Đấy là lí do mà dạo này “tác giả” quay sang đọc cuốn “The Unix programming environment” của Brian W.Kernighan và Rob Pike. Công nhận hai bác này viết sách cực hay. Cuốn sách không chỉ trình bày các công cụ hay ngôn ngữ mà quan trọng hơn là nêu bật lên được triết lí của Unix: Viết các chương trình đơn giản, mỗi chương trình chỉ làm một nhiệm vụ nhưng có khả năng tương tác tốt với nhau để thực hiện những nhiệm vụ phức tạp hơn.</p>
<p align="justify">“Tác giả” bài viết này, trong thời gian tạm thời chưa bị phân tâm bởi việc fix bug nhàm chán thường nhật, muốn trích ra đây một số phần của cuốn sách, vừa để giải trí, vừa để ôn lại C và Unix, cũng vừa là để học tập tư duy lập trình trên Unix. Đồng thời, việc làm này cũng khôi phục lại phần nào tình cảm của “tác giả” đối với công việc lập trình, vốn đã bị phai nhạt khá nhiều sau một thời gian làm việc trong một dự án chán ngắt và không hề thể hiện được một chút gì gọi là “vẻ đẹp” của lập trình Unix.</p>
<p align="justify">Tác giả cũng khuyến cáo các độc giả (nếu có <img src='http://s.wordpress.com/wp-includes/images/smilies/icon_biggrin.gif' alt=':-D' class='wp-smiley' /> ) nên tìm đọc bản tiếng Anh của cuốn sách (tác giả cũng không có bản mềm, chỉ có bản cứng), bởi trình độ kĩ thuật và tiếng Anh của tác giả đều chỉ ở mức sơ cấp.</p>
<p align="justify">Loạt bài viết này trích ra từ các chương 6, 7, 8, 9 của cuốn “The Unix programming environment”. Các chương này trình bày quá trình phát triển một số chương trình đơn giản, qua đó làm nổi bật lên các kĩ thuật và các triết lí lập trình trên Unix. Các chương trình này, theo tác giả cuốn sách, đều là các chương trình nhỏ và không có mặt trong 7th Edition của Unix. Nếu hệ điều hành hiện thời của bạn cũng không có chúng, bạn sẽ thấy chúng rất có ích. Trong trường hợp ngược lại, việc so sánh thiết kế của những chương trình sẵn có với những chương trình trong sách cũng mang lại nhiều điều bổ ích.</p>
<p align="justify">Chúng ta cùng bắt đầu với các chương trình nhập xuất dữ liệu (I/O).</p>
<h4 align="justify">Phần 1 Chương trình in ra các kí tự đặc biệt: VIS</h4>
<p align="justify"><strong>1. Standard input and output: vis</strong></p>
<p align="justify">Rất nhiều chương trình đọc dữ liệu từ một đầu vào và ghi dữ liệu ra một đầu ra. Khi đó việc sử dụng các thao tác vào ra (I/O) đối với đầu vào chuẩn (standard input) và đầu ra chuẩn (standard output) là đủ đáp ứng yêu cầu của chương trình.<br />
Chúng ta hãy bắt đầu xây dựng một chương trình đơn giản tên là vis (viết tắt của visible). vis sao chép dữ liệu từ standard input sang standard output, đồng thời hiển thị tất cả các kí tự vốn không thể in được (non-printing character) dưới dạng \nnn, trong đó nnn là giá trị octal của kí tự đó. Ví dụ: Chúng ta chuẩn bị file đầu vào x như sau:</p>
<pre>
$ cat x
abc
def
</pre>
<p align="justify">Sử dụng vis để hiện thị x, kí tự ctrl-a sẽ được hiển thị là 01, kí tự ctrl-b sẽ được hiển thị là 02.</p>
<pre>$ vis x
abc01
def02</pre>
<p align="justify">Chương trình vis sẽ có ích trong việc phát hiện các kí tự lạ được ghi vào file vì một lí do nào đó. Chú ý rằng phiên bản đầu tiên của vis sẽ chỉ nhận dữ liệu vào từ standard input chứ chưa có khả năng đọc file. Khi cần in ra nội dung của nhiều file, chúng ta có thể nhờ đến lệnh cat như sau:</p>
<pre>$ cat file1 file2 file3 … | vis</pre>
<p align="justify">Chương trình vis của chúng ta sẽ có chức năng giống với lệnh sed sau đây:</p>
<pre>$ sed –n l x
abc1
def2</pre>
<p align="justify">Tuy nhiên trong một số trường hợp sed chỉ làm việc được với các file văn bản (text), bởi vậy việc viết mới chương trình vis vẫn là cần thiết.</p>
<p align="justify">Trong phiên bản đầu tiên của vis, chúng ta sử dụng hai hàm getchar và putchar. Hàm getchar đọc vào kí tự tiếp theo từ standard input (mặc định là terminal, cũng có thể là một file hay một pipeline, các chương trình không biết điều đó). Hàm putchar ghi một kí tự ra standard output, mặc định cũng là terminal.</p>
<p align="justify">Dưới đây là phiên bản đầu tiên của vis</p>
<p><span id="more-47"></span></p>
<pre>
/* vis: make funny characters visible (version 1) */
#include
#include 

int main()
{
  int c;
  while( ( c = getchar() ) != EOF ) {

    if( isascii( c ) &amp;&amp;
        ( isprint( c ) || c == ‘\n’ || c == ‘\t’ || c == ‘ ‘ ) )
      putchar( c );
    else
      printf( “\\%03o”, c );
  }
  exit( 0 );
}</pre>
<p align="justify">Chú ý: EOF không phải một byte đọc được từ standard input. Đó là một giá trị được khai báo sao cho khác với tất cả các giá trị có thể chứa trong một byte nhằm đảm bảo sự phân biệt với các giá trị thật. Bởi vậy, biến c cần được khai báo có kiểu int thay vì char để đủ lớn để chứa được giá trị EOF.</p>
<p align="justify">Dịch và chạy chương trình như sau</p>
<pre>
$ gcc vis.c –o vis
$ ./vis
hello world
hello world07
ctrl-d
$</pre>
<p align="justify"><strong>2. Truyền tham số cho trương trình: vis phiên bản 2</strong></p>
<p align="justify">Khi chạy một chương trình C, các tham số dòng lệnh (command-line argument) được truyền vào hàm main thông qua hai tham số argc và argv. argc là số tham số dòng lệnh và argv là danh sách các tham số. argc luôn lớn hơn 0 vì theo quy ước tham số thứ nhất argv[ 0 ] là tên chương trình. Các tham số thực sự có ý nghĩa là argv[ 1 ] đến argv[ argc – 1 ]. Chú ý rằng các thao tác định hướng lại standard input và standard output bởi &gt; và &lt; được thực hiện bởi shell, do đó không được tính là các tham số dòng lệnh.</p>
<p align="justify">Để minh họa việc xử lí tham số dòng lệnh, chúng ta phát triển chương trình vis bằng cách thêm vào một tham số tùy chọn –s (viết tắt của strip). Khi chạy vis –s, các kí tự lạ trong file đầu vào sẽ bị loại bỏ. Tính năng này rất có ích cho việc “làm sạch” các file đến từ các hệ điều hành khác, chẳng hạn các hệ điều hành sử dụng CRLF làm kí tự xuống dòng thay vì kí tự new line. Dưới đây là mã nguồn của phiên bản mới của vis</p>
<pre>
/* vis: make funny characters visible (version 2) */
#include
#include 

int main( int argc, char *argv[ ] )
{
  int c, strip = 0;

  if( ( argc &gt; 1 ) &amp;&amp; ( strcmp( argv[ 1 ], “-s” ) == 0 )
    strip = 1;

  while( ( c = getchar() ) != EOF ) {

    if( isascii( c ) &amp;&amp;
        ( isprint( c ) || c == ‘\n’ || c == ‘\t’ || c == ‘ ‘ ) )
      putchar( c );
    else if( ! strip )
      printf( “\\%03o”, c );
  }
  exit( 0 );
}</pre>
<p align="justify"><strong>3. Truy nhập file: vis phiên bản 3<br />
</strong>Phiên bản 1 và 2 của vis chỉ đọc dữ liệu vào từ standard input. Bây giờ chúng ta sẽ phát triển vis để có thể đọc dữ liệu vào trực tiếp từ các file. Khi chạy lệnh</p>
<pre>
$ vis file1 file2 …</pre>
<p align="justify">vis sẽ đọc vào nội dung của từng file và xử lí thay vì đọc dữ liệu từ standard input. Tất nhiên khi không có tên file nào được truyền vào thì vis vẫn đọc dữ liệu từ standard input. Các hàm thường được sử dụng để xử lí file là: fopen, getc, putc.<br />
Một số điểm cần lưu ý: Khi chạy một chương trình, sẽ có ba file được mở sẵn với các con trỏ file là stdin, stdout và stderr. Chúng có thể được sử dụng ở bất cứ đâu mà một biến kiểu FILE* có thể có mặt. Hàm getchar() tương đương với getc( stdin ) và hàm putchar( c ) tương đương với putc( c, stdout ).<br />
Dưới đây là phiên bản 3 của vis. Nếu có mặt các tham số dòng lệnh là các tên file, chúng sẽ được xử lí lần lượt. Nếu không có mặt tham số dòng lệnh nào, vis vẫn đọc dữ liệu từ standard input.</p>
<pre>
/* vis: make funny characters visible (version 3) */
#include
#include 

int strip = 0;

int main( int argc, char *argv[ ] )
{

  int i;
  FILE *fp;
  void vis( FILE* );

  while( ( argc &gt; 1 ) &amp;&amp; ( argv[1 ][ 0 ] == ‘-‘ ) ) {

    switch( argv[ 1 ][ 1 ] ) {

      case ‘s’: /* -s: strip funny chars */
        strip = 1;
        break;

      default:
        fprintf( stderr, “%s: unknown arg %s\n”, argv[ 0 ], argv[ 1 ] );
        exit( 1 );
    }

    argc--;
    argv++;
  }

  if( argc == 1 )
    vis( stdin );
  else
    for( i = 1; i &lt; argc; i++ ) {

      if( ( fp = fopen( argv[ i ], “r” ) ) == NULL ) {
        fprintf( stderr, “%s: cannot open %s\n”, argv[ 0 ], argv[ i ] );
        exit( 1 );
      } else {
        vis( fp );
        fclose( fp );
      }
    }
  exit( 0 );
}

/* make chars visible in FILE *fp */
void vis( FILE *fp )
{
  int c;

  while( ( c = getc( fp ) ) != EOF ) {

    if( isascii( c ) &amp;&amp;
        ( isprint( c ) || c == ‘\n’ || c == ‘\t’ || c == ‘ ‘ ) )
      putchar( c );
    else if( ! strip )
      printf( “\\%03o”, c );
  }
}</pre>
<p align="justify">Chúng ta dùng một vòng lặp while để xử lí các tham số dòng lệnh với giả thiết rằng các tham số tùy chọn (optional argument, ví dụ -s) xuất hiện trước. Mặc dù phiên bản hiện thời của vis chỉ có một tham số tùy chọn là –s nhưng vòng lặp while ở trên có khả năng xử lí được nhiều tham số tùy chọn. Một số hệ điều hành cung cấp hàm getopt để xử lí các tham số dòng lệnh. Hãy tham khảo hàm này trước khi tự viết.<br />
Một điều cần chú ý là vis sẽ kết thúc khi không thể mở được một trong các file đầu vào. Thiết kế này là chấp nhận được bởi vis chủ yếu được sử dụng một cách tương tác và với chỉ một file đầu vào.</p>
<p align="justify"><strong>4. Một số hướng phát triển của vis</strong></p>
<p align="justify">- Phát triển vis sao cho các kí tự tab, backslash, backspace, formfeed…được in ra dưới dạng biểu diễn của ngôn ngữ C như \t, \\, \b, \f và các kí tự blank và xuống dòng cũng được đánh dấu. So sánh chương trình với lệnh</p>
<pre>
$ sed –n l</pre>
<p align="justify">- Phát triển vis sao cho các dòng quá dài bị cắt đi, chỉ được hiển thị với một độ dài hợp lí.</p>
<p align="justify">- Phát triển vis sao cho khi chạy chương trình với tham số -sn như sau</p>
<pre>
$ vis –sn</pre>
<p align="justify">sẽ chỉ in ra các xâu được tạo thành bởi n hay nhiều hơn các kí tự có thể in được (printable character). Nghĩa là các kí tự không in được và các xâu gồm các kí tự in được nhưng quá ngắn đều bị bỏ qua. Tính năng này rất hữu ích trong việc trích ra các phần văn bản từ các file không phải văn bản (non-text file), ví dụ các chương trình chạy (executable program). Một số hệ điều hành cung cấp chương trình strings thực hiện nhiệm vụ này. Suy nghĩ xem có cần thiết viết một chương trình hoàn toàn mới thay vì sửa đổi vis hay không?</p>
<p align="justify">- Viết một chương trình có tên printable in ra tên các file chỉ chứa các kí tự in được. Tên các file được đưa vào bằng các tham số dòng lệnh. Chương trình này có ích khi cần in nhiều file cùng lúc như sau</p>
<pre>
$ pr `printable *` | lpr</pre>
<p align="justify">Dùng lệnh man để xem chức năng của hai lệnh pr và lpr</p>
<p align="justify"><strong>Phần tiếp theo: Chương trình hiển thị nội dung file theo từng trang màn hình: P</strong></p>
<img alt="" border="0" src="http://feeds.wordpress.com/1.0/categories/openandfree.wordpress.com/47/" /> <img alt="" border="0" src="http://feeds.wordpress.com/1.0/tags/openandfree.wordpress.com/47/" /> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gocomments/openandfree.wordpress.com/47/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/comments/openandfree.wordpress.com/47/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/godelicious/openandfree.wordpress.com/47/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/delicious/openandfree.wordpress.com/47/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gostumble/openandfree.wordpress.com/47/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/stumble/openandfree.wordpress.com/47/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/godigg/openandfree.wordpress.com/47/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/digg/openandfree.wordpress.com/47/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/goreddit/openandfree.wordpress.com/47/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/reddit/openandfree.wordpress.com/47/" /></a> <img alt="" border="0" src="http://stats.wordpress.com/b.gif?host=openandfree.wordpress.com&blog=1590880&post=47&subd=openandfree&ref=&feed=1" /></div>]]></content:encoded>
			<wfw:commentRss>http://openandfree.wordpress.com/2008/01/17/unix-programming-with-standard-io/feed/</wfw:commentRss>
		<slash:comments>2</slash:comments>
	
		<media:content url="http://0.gravatar.com/avatar/0b7240ced9e7e663cff734d741f37158?s=96&#38;d=identicon&#38;r=G" medium="image">
			<media:title type="html">kiennguyen</media:title>
		</media:content>
	</item>
		<item>
		<title>So sánh C++ và C (1) &#8211; Classes and methods</title>
		<link>http://openandfree.wordpress.com/2007/12/21/so-sanh-c-va-c-1-classes-and-methods/</link>
		<comments>http://openandfree.wordpress.com/2007/12/21/so-sanh-c-va-c-1-classes-and-methods/#comments</comments>
		<pubDate>Fri, 21 Dec 2007 07:26:55 +0000</pubDate>
		<dc:creator>Hoang Tran</dc:creator>
				<category><![CDATA[C/C++]]></category>

		<guid isPermaLink="false">http://www.openandfree.org/blog/?p=40</guid>
		<description><![CDATA[Bài viết này là một trong hai bài viết so sánh giữa C và C++ bằng cách so sánh các đoạn mã trong C++ với đoạn mã tương ứng của nó được viết trong C. So sánh này sẽ cho bạn cái nhìn tốt hơn về sự khác biệt của performance giữa C và C++. [...]<img alt="" border="0" src="http://stats.wordpress.com/b.gif?host=openandfree.wordpress.com&blog=1590880&post=45&subd=openandfree&ref=&feed=1" />]]></description>
			<content:encoded><![CDATA[<div class='snap_preview'><br /><p style="text-align:justify;font-size:10pt;font-family:Verdana;">Bài viết này là một trong hai bài viết so sánh giữa C và C++ bằng cách so sánh các đoạn mã trong C++ với đoạn mã tương ứng của nó được viết trong C. So sánh này sẽ cho bạn cái nhìn tốt hơn về sự khác biệt của performance giữa C và C++. </p>
<p style="text-align:justify;font-size:10pt;font-family:Verdana;">Trong bài viết đầu tiên, chúng ta sẽ xem xét ảnh hưởng tới performance của việc thực thi các phương thức trong C++. So sánh này được thực hiện bằng việc so sánh đoạn mã C++ và đoạn mã C tương ứng. </p>
<p><span id="more-45"></span></p>
<pre>
// Example class A contains regular and
// static member variables and methods.
class A
{
private:
  int m_x;
  static int g_y;
  int m_z;

  // Should be invoked when the object ends
  void InformEnd();
public:
  A(int x);
  ~A();

  void UpdateX(int newX);
  static void UpdateY(int newY);
};

// Initialization of the static variable
int A::g_y = 0;

// The non-static member variables
// are initialized in the constructor
A::A(int x)
{
  m_x = x;
  m_z = 0;
}

// Destructor invokes a private variable
A::~A()
{
  InformEnd();
}

// UpdateX checks the value of X against
// a static variable before updating the value
void A::UpdateX(int newX)
{
  if (g_y != 0 &amp;&amp; m_x UpdateX(8);

    // Example of a direct access
    a.UpdateX(9);

    // Example of static method call
    A::UpdateY(1000);

    // Deleting the object
    delete pA;
}
</pre>
<p style="text-align:justify;font-size:10pt;font-family:Verdana;">Đoạn mã C sau đấy sẽ cung cấp một thể hiện tương ứng với đoạn mã C++ phía trên. Class trong C++ được chuyển tương ứng thành struct trong C. </p>
<pre>
/*
This code maps from the C++ code to the equivalent C code.
Mapping of the following entities is covered:
- classes                 - methods
- this pointer            - member variables
- constructors            - static methods
- destructors             - static variables
*/
#include
#include
#define TRUE 1
#define FALSE 0

typedef int BOOLEAN;

/*
Structure A represents the class A. Only the non-static member
variables are present in the structure
*/
struct A
{
  int m_x;
  int m_z;
};

/* Notice that g_y is not a part of struct A. Its a separate global variable. */
int g_y = 0;

/*
Prototype for the InformEnd method. The C++ version of this method
did not have any parameters but the C mapped function needs the this
pointer to obtain the address of the object. Note that all non-static
methods in the C++ code would map to a C function the additional this
pointer as the first parameter.
*/
void InformEnd(A *this_ptr);

/*
The constructor maps to function with the this pointer and the size of the
structure as parameters. this_ptr passed to the constructor is NULL when
the operator new is used to create the object. this_ptr contains a valid
pointer if the memory for the object to be constructed is already
allocated. (e.g. local variable or part of another structure.)
*/

A *A_Constructor(A *this_ptr, int x)
{
  /*Check if memory has been allocated for struct A. */
  if (this_ptr == NULL)  {
    /*Allocate memory of size A. */
    this_ptr = (A *) malloc(sizeof(A));
  }

  /* Once the memory has been allocated for A, initialise members of A. */
  if (this_ptr)  {
    this_ptr-&gt;m_x = x;
    this_ptr-&gt;m_z = 0;
  }

  return this_ptr;
}

/*
The following function is equivalent to a destructor. The this
pointer and a dynamic flag are passed as the two parameters to
this function. The dynamic flag is set to true if the object is
being deleted using the delete operator.
*/

void A_Destructor(A *this_ptr, BOOLEAN dynamic)
{
  InformEnd(this_ptr);

  /* If the memory was dynamically allocated for A, explicitly free it. */
  if (dynamic) {
    free(this_ptr);
  }
}

/*
A pointer this is passed as first argument. All member variables
in the code will be accessed through an indirecion from the this
pointer. Notice that static variables are accessed directly as
they do not belong to any instance.
*/

void A_UpdateX(A *this_ptr, int newX)
{
  if (g_y != 0 &amp;&amp; this_ptr-&gt;m_x m_x = newX;
  }
}

/*
Notice that this is not passed here. This is so because
A_UpdateY is a static function. This function can only access
other static functions and static or global variables. This
function cannot access any member variables or methods of class A
as a static function does not correspond to an instance.
*/

void A_UpdateY(int newY)
{
  g_y = newY;
}

main()
{
    /*
    Dynamically allocate memory by passing NULL in this arguement.
    Also initialize members of struct pointed to by pA.
    */
    A *pA = A_Constructor(NULL, 5);

    /* Define local variable a of type struct A. */
    A a;

    /*
    Initialize members of struct variable a. Note that the
    constructor is called with the address of the object as
    a has been pre-allocated on the stack.
    */
    A_Constructor(&amp;a, 6);

    /*
    Method invocations in C++ are handled by calling the
    corresponding C functions with the object pointer.
    */
    A_UpdateX(pA, 8);
    A_UpdateX(&amp;a, 9);

    /* UpdateY is a static method, so object pointer is not passed */
    A_UpdateY(1000);

    /*
    Delete memory pointed to by pA (explicit delete in
    original code).
    */
    A_Destructor(pA, TRUE);

    /*
    Since memory was allocated on the stack for local struct
    variable a, it will be deallocated when a goes out of scope.
    The destructor will also be invoked. Notice that dynamic flag
    is set to false so that the destructor does not try to
    free memory.
    */
    A_Destructor(&amp;a, FALSE);

}
</pre>
<p style="text-align:justify;font-size:10pt;font-family:Verdana;"><strong>C++ Method Invocation</strong>: Tất cả các phương thức trong C++ được dịch thành các hàm trong C với một tham số bổ sung. Đó có thể là điểm gây khác biệt lớp về performance. Tuy nhiên trong thực tế thì đoạn mã trong C cũng phải truy nhập vào cấu trúc dữ liêu chung thông qua một chỉ số mảng hoặc một cơ chế nào đó.</p>
<p style="text-align:justify;font-size:10pt;font-family:Verdana;"><strong>Khởi tạo đối tượng</strong>: Bất cứ khi nào một đối tượng được khởi tạo, C++ sẽ thực thi hàm khởi tạo (constructor). Đôi khi thì việc đó cũng thêm một chút phí tổn. Phí tổn đó có thể giảm đi bằng cách định nghĩa ham khởi tạo là inline. Tuy nhiên trong hầu hết các trường hợp, hàm khởi tạo thực sự thay thế một hàm mà được sử dụng để khởi tạo cấu trúc dữ liệu trong chương trình C.</p>
<p style="text-align:justify;font-size:10pt;font-family:Verdana;">Nếu chương trình khai báo rất nhiều biến toàn cục, khởi tạo đối tượng có thể tiêu tốn nhiều lúc khởi tạo chương trình. C++ tham gia việc khởi tạo tất cả các đối tượng trước khi hàm main được gọi</p>
<p style="text-align:justify;font-size:10pt;font-family:Verdana;"><strong>Hủy đối tượng</strong> Bạn có thể thấy từ đoạn mã C phía trên, bất cứ khi nào đối tượng ra khỏi scope của nó hoặc là bị delete thì C++ sẽ thực hiện hàm hủy của đối tượng đó. Sự tiêu tốn này có thể giảm đi bằng việc chỉ định nghĩa hàm hủy khi chúng thực sự cần thiết (ví dụ một vài hành động cần thiết khi đối tượng bị hủy). Các hàm hủy inline cũng có thể được sử dụng.</p>
<p style="text-align:justify;font-size:10pt;font-family:Verdana;"><strong>Static access</strong>: Đoạn mã C phía trên chỉ ra rằng các hàm thành viên và biến tĩnh (static) không tích hợp với một đối tượng cụ thể nào cả. Vì vậy chúng có thể truy nhập trực tiếp không thông qua đối tượng. Nó có thể rất hữu ích trong việc định nghĩa một phương thức mà cần hàm  có calling convention của C. Một ví dụ tốt cho các hàm thành viên tĩnh là để thể hiện các hàm interrupt service routines (ISRs). ISR handlers cần phải là các hàm C. C++ static functions có thể trực tiếp sử dụng bởi các ISR handlers.</p>
<p style="text-align:justify;font-size:10pt;font-family:Verdana;">Tham khảo: http://www.eventhelix.com/RealtimeMantra/basics/ComparingCPPAndCPerformance.htm</p>
<img alt="" border="0" src="http://feeds.wordpress.com/1.0/categories/openandfree.wordpress.com/45/" /> <img alt="" border="0" src="http://feeds.wordpress.com/1.0/tags/openandfree.wordpress.com/45/" /> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gocomments/openandfree.wordpress.com/45/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/comments/openandfree.wordpress.com/45/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/godelicious/openandfree.wordpress.com/45/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/delicious/openandfree.wordpress.com/45/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gostumble/openandfree.wordpress.com/45/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/stumble/openandfree.wordpress.com/45/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/godigg/openandfree.wordpress.com/45/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/digg/openandfree.wordpress.com/45/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/goreddit/openandfree.wordpress.com/45/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/reddit/openandfree.wordpress.com/45/" /></a> <img alt="" border="0" src="http://stats.wordpress.com/b.gif?host=openandfree.wordpress.com&blog=1590880&post=45&subd=openandfree&ref=&feed=1" /></div>]]></content:encoded>
			<wfw:commentRss>http://openandfree.wordpress.com/2007/12/21/so-sanh-c-va-c-1-classes-and-methods/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
	
		<media:content url="http://1.gravatar.com/avatar/f6f88159a87ae5eb23d369e775bf0e4a?s=96&#38;d=identicon&#38;r=G" medium="image">
			<media:title type="html">hoangtran</media:title>
		</media:content>
	</item>
		<item>
		<title>nested class, nested function và một ứng dụng thú vị của function object</title>
		<link>http://openandfree.wordpress.com/2007/12/20/nested-class-nested-function-va-m%e1%bb%99t-%e1%bb%a9ng-d%e1%bb%a5ng-thu-v%e1%bb%8b-c%e1%bb%a7a-function-object/</link>
		<comments>http://openandfree.wordpress.com/2007/12/20/nested-class-nested-function-va-m%e1%bb%99t-%e1%bb%a9ng-d%e1%bb%a5ng-thu-v%e1%bb%8b-c%e1%bb%a7a-function-object/#comments</comments>
		<pubDate>Wed, 19 Dec 2007 18:16:39 +0000</pubDate>
		<dc:creator>kiennguyen</dc:creator>
				<category><![CDATA[C/C++]]></category>
		<category><![CDATA[function object]]></category>
		<category><![CDATA[nested class]]></category>
		<category><![CDATA[nested function]]></category>

		<guid isPermaLink="false">http://www.openandfree.org/blog/?p=39</guid>
		<description><![CDATA[Nguồn: http://www.gotw.ca/gotw/058.htm
Bài viết này không trình bày chi tiết về nested class trong C++ mà chỉ tập trung vào các kĩ thuật sử dụng nested class và function object để mô phỏng các nested function, một yếu tố không có trong C++. Các chi tiết về nested class có thể tìm thấy trong nhiều cuốn [...]<img alt="" border="0" src="http://stats.wordpress.com/b.gif?host=openandfree.wordpress.com&blog=1590880&post=44&subd=openandfree&ref=&feed=1" />]]></description>
			<content:encoded><![CDATA[<div class='snap_preview'><br /><p align="justify">Nguồn: <a href="http://www.gotw.ca/gotw/058.htm">http://www.gotw.ca/gotw/058.htm</a></p>
<p align="justify">Bài viết này không trình bày chi tiết về nested class trong C++ mà chỉ tập trung vào các kĩ thuật sử dụng nested class và function object để mô phỏng các nested function, một yếu tố không có trong C++. Các chi tiết về nested class có thể tìm thấy trong nhiều cuốn sách C++ khác, ví dụ cuốn Thinking in C++, tập 1.</p>
<p align="justify">Bài viết đưa ra ba câu hỏi và sau đó lần lượt đi tìm các câu trả lời cho chúng. Ba câu hỏi là:</p>
<p align="justify">1- Nested class là gì? Tại sao chúng ta cần các nested class?<br />
2- Local class là gì? Tại sao chúng ta cần các local class?<br />
3- Trong C++ không có khái niệm nested function. Bởi vậy, chúng ta không thể viết một đoạn mã như sau</p>
<pre>int f( int i )
{
  int j = i*2;
  int g( int k )
  {
    return j+k;
  }
  j += 4;
  return g( 3 );
}</pre>
<p align="justify">Hãy đưa ra một giải pháp mô phỏng các hàm f và g sao cho đạt được một “hiệu ứng” tương tự như đoạn mã trên.</p>
<p align="justify"><strong>Trả lời</strong></p>
<p align="justify">C++ có rất nhiều công cụ hữu ích dùng để ẩn thông tin (information hiding) và quản lí sự phụ thuộc mã nguồn (dependency management). Các đoạn mã sau đây có thể chưa hoàn toàn chính xác về mặt cú pháp, chúng được dùng để minh họa cho các kĩ thuật thiết kế mà thôi.</p>
<p align="justify"><strong>1- Nested class là gì? Tại sao chúng ta cần nested class?</strong></p>
<p align="justify">Nested class là một class được “viết” (enclosed) bên trong phạm vi (scope) của một class khác.</p>
<pre>// Ví dụ 1: Nested class
//
  class OuterClass
  {
    class NestedClass
    {
      // ...
    };
    // ...
  };</pre>
<p align="justify">Trong đoạn mã trên, NestedClass là một nested class được “viết” bên trong class OuterClass. Các nested class rất hữu ích cho việc tổ chức mã nguồn, quản lí quyền truy nhập (access) và các phụ thuộc (dependencies). Các nested class tuân theo các quy tắc thông thường về quyền truy nhập giống như các dữ liệu thành phần và các hàm thành phần. Tức là, nếu NestedClass được khai báo là public thì chúng ta có thể sử dụng nó từ bất cứ đâu thông qua tên gọi OuterClass::NestedClass. Ngược lại, nếu NestedClass được khai báo là private thì chỉ có các thành phần và các hàm bạn (friends) của OuterClass là có quyền truy nhập đến nó. Thông thường, các nested class chứa các cài đặt riêng cho OuterClass, do đó thường được khai báo là private.</p>
<p align="justify">Chú ý rằng nested class khác với namespace. Các namespace chỉ thuần túy nhóm các tên lại với nhau chứ không mang lại khả năng quản lí quyền truy nhập. Nếu bạn muốn quản lí quyền truy nhập tới một lớp, một trong các giải pháp là viết nó thành nested class trong một class khác.</p>
<p align="justify"><strong>2- Local class là gì? Tại sao chúng ta cần các local class? </strong></p>
<p align="justify">Local class là một class được định nghĩa bên trong một hàm thông thường hoặc một hàm thành phần (member function). Trong ví dụ sau đây, LocalClass là một local class được định nghĩa bên trong một hàm thông thường có tên là f.</p>
<pre>// Ví dụ 2: Local class
//
  int f()
  {
    class LocalClass
    {
      // ...
    };
    // ...
  };</pre>
<p align="justify">Giống như nested class, local class là một công cụ hữu ích phục vụ việc quản lí những sự phụ thuộc về mã nguồn (code dependencies). Trong ví dụ 2, chỉ có đoạn mã trong thân hàm f mới được phép sử dụng LocalClass. LocalClass thường chứa những cài đặt riêng cho hàm f nên không cần thiết phải có khả năng truy nhập được từ bên ngoài.</p>
<p align="justify">Bạn có thể sử dụng local class gần như trong mọi tình huống có thể sử dụng class thông thường. Một ngoại lệ quan trọng cần ghi nhớ là: Các local class không thể đóng vai trò tham số kiểu (template parameter). Ví dụ dưới đây trích từ tài liệu chuẩn C++:</p>
<pre>A local type, a type with no linkage, an unnamed
type or a type compounded from any of these types
shall not be used as a template-argument for a
template type-parameter. [Example:
    template
    class X { /* ... */ };

    void f()
    {
      struct S { /* ... */ };
      X x3;  // error: local type used as
                //  template-argument
      X x4; // error: pointer to local type
                //  used as template-argument
    }
  -end example]</pre>
<p align="justify">Tóm lại, cả nested class lẫn local class đều là những công cụ hữu ích của C++ dùng để ẩn thông tin và quản lí quyền truy nhập và các phụ thuộc.</p>
<p align="justify"><strong>Nested Funtion</strong></p>
<p align="justify">Một vài ngôn ngữ (không phải C++) cho phép chúng ta viết các nested function. Giống như các nested class, nested function là một function được viết bên trong một function khác. Những đặc điểm quan trọng của nested function là:</p>
<p align="justify">- Các nested function có quyền truy nhập đến các biến cục bộ của hàm chứa nó.<br />
- Các nested function là “cục bộ”, nghĩa là không thể truy nhập tới chúng từ bên ngoài, trừ khi có một con trỏ trỏ đến nested function được cung cấp bởi hàm chứa.</p>
<p align="justify">Nếu như các nested class hữu ích bởi chúng cho phép điều kiển sự “ẩn hiện” (visibility) của một lớp thì các nested function hữu ích bởi chúng cho phép điều khiển sự “ẩn hiện” của một hàm.</p>
<p align="justify"><strong>Trả lời cho câu hỏi 3: Các giải pháp sử dụng class để mô phỏng nested function trong C++</strong></p>
<p align="justify">Chú ý: “mô phỏng” ở đây được hiểu theo nghĩa là: Xây dựng một class g bên trong một hàm f, sao cho f có thể sử dụng g như một nested function</p>
<pre>void f()
{
  class g { … };  g();
}</pre>
<p align="justify">Nói đến một class được sử dụng như một function, chúng ta nghĩ ngay đến các function object. Giải pháp đầu tiên mà hầu hết mọi người sẽ đưa ra là:</p>
<p><span id="more-44"></span></p>
<pre>// Giải pháp 3(a): Một giải pháp thô sử dụng function object
//
//
  int f( int i )
  {
    int j = i*2;
    class g_
    {
      public:
        int operator()( int k )
        {
          return j+k; // ERROR!!!: Không thể sử dụng j bên trong g_
        }
    } g;

    j += 4;

    return g( 3 ); // f sử dụng g như một nested function
  }</pre>
<p align="justify">Ý tưởng ở đây là mô phỏng nested function bởi một local class có tên là g_, sau đó gọi operator() của g_. <strong>(Xem lại bài viết: STL Function Object và các ứng dụng(1) để biết chi tiết về cách viết một function object)</strong>. Đây là một ý tưởng hay nhưng đáng tiếc là đoạn mã trên không chạy được! Lí do là một local class không thể sử dụng các biến của hàm bên ngoài (ở đây là biến j). Một giải pháp cho vấn đề này là truyền các biến của hàm bên ngoài vào trong local class thông qua các thành phần dữ liệu của class đó.</p>
<pre>// Giải pháp 3(b): Sử dụng function object.
// Thành phần dữ liệu của local class là các references trỏ tới
// các biến cục bộ của hàm bên ngoài (phức tạp, khó bảo trì)
//
  int f( int i )
  {
    int j = i*2;
    class g_
    {
      public:
        g_( int &amp;j ) : j_( j ) { }
        int operator()( int k )
        {
          return j_+k; // sử dụng j thông qua reference
        }
      private:
        int &amp;j_;
    } g( j );

    j += 4;

    return g( 3 );
  }</pre>
<p align="justify">Bây giờ thì local class g_ đã có thể sử dụng biến j của hàm bên ngoài thông qua thành phần dữ liệu j_ của nó và hàm f() ở trên đã chạy đúng. Tuy nhiên nhược điểm của giải pháp này là rất khó có thể mở rộng. Trong trường hợp class g_ cần sử dụng một biến khác nữa của hàm f() ngoài biến j (giả sử là biến k kiểu int). Khi đó chúng ta phải thực hiện những thao tác sau đây:</p>
<p align="justify">- Thêm vào class g_ một thành phần dữ liệu int &amp;k_;<br />
- Thêm tham số int k cho constructor của g_;<br />
- Thêm một phép khởi tạo cho k_: k_( k );</p>
<p align="justify">Sô thao tác cần thực hiện sẽ tăng lên rất nhiều nếu có nhiều local class trong f(). Vậy, chúng ta cần tìm ra một giải pháp tốt hơn.</p>
<p align="justify"><strong>Một giải pháp tốt hơn</strong></p>
<p align="justify">Hàm f được cải tiến bằng cách chuyển các biến cục bộ của nó thành các thành phần dữ liệu public của lớp g_</p>
<pre>// Giải pháp 3(c): Một giải pháp tốt hơn
//
  int f( int i )
  {
    class g_
    {
      public:
        int j;
        int operator()( int k )
        {
          return j+k;
        }
    } g;

    g.j = i*2;
    g.j += 4;

    return g( 3 );
  }</pre>
<p align="justify">Bây giờ thì hàm f đã trở nên đẹp đẽ và dễ bảo trì, phát triển. Giải pháp này gợi cho chúng ta suy nghĩ: Tại sao không “mô phỏng” các nested function của f() bởi các hàm thành phần x(), y(), z() của lớp g_? Đoạn mã sau đây hiện thực hóa ý tưởng này. Lớp g_ được đổi tên thành Local_ để mang tính mô tả tốt hơn</p>
<pre>// Giải pháp 3(d): Mô phỏng nested function bằng cách hàm thành phần
//
  int f( int i )
  {

    class Local_
    {
      public:
        int j;
        int g( int k )
        {
          return j+k;
        }
        void x() { /* ... */ }
        void y() { /* ... */ }
        void z() { /* ... */ }
    } local;

    local.j = i*2;
    local.j += 4;
    local.x();
    local.y();
    local.z();

    return local.g( 3 );
  }</pre>
<p align="justify">Giải pháp này không sử dụng function object. Nhược điểm của nó là j không được khởi tạo một cách linh hoạt do lớp Local_ không có constructor.</p>
<p align="justify"><strong>Giải pháp hoàn thiện</strong></p>
<p align="justify">Nếu f không nhất thiết phải là một hàm thông thường mà chỉ cần được sử dụng như một hàm thông thường, chúng ta có thể xây dựng f dưới dạng một function object và xây dựng các nested function dưới dạng các hàm thành phần như sau:</p>
<pre>// Giải pháp 3(e): Một giải pháp hoàn thiện. Dễ bảo trì, phát triển
//
//
  class f
  {
      int retval; // Giá trị trả về của “hàm” f
      int j;

      //Các hàm thành phần của lớp f
      //g(), x(), y(), z() có vai trò tương tự như các nested function
      int g( int k ) { return j + k; };
      void x() { /* ... */ }
      void y() { /* ... */ }
      void z() { /* ... */ }

    public:
      f( int i ) // constructor
        : j( i*2 )
      {
        j += 4;
        x();
        y();
        z();
        retval = g( 3 );
      }
      operator int() // operator() trả về giá trị cho “hàm” f
      {
        return retval;
      }
  };</pre>
<p align="justify">Giải pháp 3(e) là một giải pháp hoàn thiện cho việc mô phỏng nested function g cho một hàm f thông thường. Nếu f không phải là một hàm thông thường mà là một hàm thành phần của một lớp C nào đó thì sao? Khi đó, chúng ta mong muốn mô phỏng được đoạn mã sau đây, trong đó g là một nested function của hàm thành phần f của lớp C (tất nhiên đoạn mã này là không hợp lệ trong C++, vì C++ không cho phép nested function)</p>
<pre>// Đoạn mã cần mô phỏng: Một nested function bên trong một hàm thành phần
// Chú ý: Đoạn mã chỉ có tính minh họa, không hợp lệ trong C++
//
//
  class C
  {
      int data_;
    public:
      /* f là hàm thành phần của lớp C */
      int f( int i )
      {
        // g là một nested function của f
        int g( int i ) { return data_ + i; }
        return g( data_ + i*2 );
      }
  };</pre>
<p align="justify">“Bắt chước” giải pháp 3(e), cộng với một chút điều chỉnh, chúng ta có giải pháp 4(a) sau đây:</p>
<p align="justify">- Xây dựng C_f như một function object và là một nested class bên trong lớp C<br />
- Xây dựng g như một hàm thành phần của C_f<br />
- Hàm thành phần f của C gọi đến C_f</p>
<pre>// Giải pháp 4(a): Giải pháp hoàn thiện, giống 3(e) nhưng áp dụng cho hàm thành phần
//
//
  class C
  {
      int data_;
      friend class C_f;

    public:
      int f( int i );
  };

  class C_f
  {
      C* self;
      int retval;
      int g( int i ) { return self-&gt;data_ + i; }

    public:
      C_f( C* c, int i ) : self( c )
      {
        retval = g( self-&gt;data_ + i*2 );
      }
      operator int() { return retval; }
  };

  int C::f( int i ) { return C_f( this, i ); }</pre>
<p align="justify"><strong>Kết luận</strong></p>
<p align="justify">Cũng giống như những bài viết khác trong cùng loạt bài GotW của Herb Sutter, bài viết này đã đưa ra một yêu cầu thiết kế thú vị, sau đó tiến hành xem xét đánh giá những giải pháp khác nhau để cuối cùng chọn ra một giải pháp tốt nhất. Bài viết cung cấp nhiều kinh nghiệm lập trình C++, cũng như cho thấy một ứng dụng thú vị nữa của các function object.</p>
<img alt="" border="0" src="http://feeds.wordpress.com/1.0/categories/openandfree.wordpress.com/44/" /> <img alt="" border="0" src="http://feeds.wordpress.com/1.0/tags/openandfree.wordpress.com/44/" /> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gocomments/openandfree.wordpress.com/44/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/comments/openandfree.wordpress.com/44/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/godelicious/openandfree.wordpress.com/44/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/delicious/openandfree.wordpress.com/44/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gostumble/openandfree.wordpress.com/44/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/stumble/openandfree.wordpress.com/44/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/godigg/openandfree.wordpress.com/44/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/digg/openandfree.wordpress.com/44/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/goreddit/openandfree.wordpress.com/44/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/reddit/openandfree.wordpress.com/44/" /></a> <img alt="" border="0" src="http://stats.wordpress.com/b.gif?host=openandfree.wordpress.com&blog=1590880&post=44&subd=openandfree&ref=&feed=1" /></div>]]></content:encoded>
			<wfw:commentRss>http://openandfree.wordpress.com/2007/12/20/nested-class-nested-function-va-m%e1%bb%99t-%e1%bb%a9ng-d%e1%bb%a5ng-thu-v%e1%bb%8b-c%e1%bb%a7a-function-object/feed/</wfw:commentRss>
		<slash:comments>2</slash:comments>
	
		<media:content url="http://0.gravatar.com/avatar/0b7240ced9e7e663cff734d741f37158?s=96&#38;d=identicon&#38;r=G" medium="image">
			<media:title type="html">kiennguyen</media:title>
		</media:content>
	</item>
	</channel>
</rss>