Dec 19, 2012

Sự khác biệt về hàm main của C và C++

Thoạt đầu tưởng chừng như không có sự khác biệt giữa 2 ngôn ngữ với hàm 'main': hàm đặc biệt quan trọng trong chương trình. Nhưng thưc tế lại khác xíu.
Cho 2 đoạn mã sau.
Đoạn 1: Viết bằng c:
#include <stdio.h>
float main(int a, int b, int c)
{
    printf("Chao cac ban\n");
}
Đoạn 2: Viết bằng cpp:
#include <iostream>
using namespace std;
int main( int n, char x, float t) 
{
    cout << "Chao cac ban" <<endl;
    return 0;
}
Cả 2 đoạn mã điều chạy được, tuy nhiên nếu compile đoạn mã cpp sẽ dính 2 cái Warning. Còn đối với c thì không có gì. Điều thú vị hơn là nếu trong đoạn mã cpp ta thay đổi kiểu trả về của 'main' từ 'int' sang 'float' thì lại dính error.
Đây là lí do:
  • Trong C, nó chỉ yêu cầu tồn tại một hàm tên 'main', vậy là đủ, nó không quan tâm đến chuyện tham số đầu vào hay kết quả trả về.
  • Trong C++, nó khuyến cáo sử dụng 2 mẫu:
    int main(int argc, char** argv); // hoặc
    int main() //
Nếu không rơi vào 2 trường hợp này: thay đổi số lượng tham số sẽ gây warning, còn thay đổi kiểu trả về gây ra error.

Dec 18, 2012

Giải quyết vấn đề laptop nóng và hao pin khi dùng Linux

Một trong những vấn đề khá đau đầu khi sử dụng Linux trên laptop đó là hiện tượng nóng máy và pin xài không lâu. Qua một năm ngồi mày mò, chinh chiến, làm đủ thứ trò đồi bại với cái máy, cuối cùng mình cũng tìm ra được một số giải pháp xử lý vấn đề này.
Bài viết này tập hợp các thủ thuật, phương pháp nhằm giải quyết các vấn đề sau trên linux
  1. Laptop quá nóng khi sử dụng trên Linux.
  2. Thời lượng dùng pin trên Linux quá ngắn.
  3. Chế độ tiết kiệm pin của Linux không ổn định.

1. Sử dụng các tools:
  1. PowerTOP:Một ứng dụng được viết của Intel giúp giải quyết các vấn đề về sử dụng tài nguyên trên Linux. Khá hay dành cho máy nào dành kiến trức Intel.
  2. cpufrequtils:Quản lí tài nguyên CPU.
  3. pm-utils: Xem hướng dẫn chi tiết ở đây: Pm-utils ArchWiki
  4. lm_sensors: Cách dùng khá đơn giản. Chỉ việc tải về và chạy lệnh "sensors-detect" rồi nhấn 'y' mỗi khi chương trình thông báo là xong.
  5. laptop-mode-tools: Hướng dẫn sử dụng https://wiki.archlinux.org/index.php/Laptop_Mode_Tools. Đây là chương trình khá hiệu quả và có các tùy chỉnh rất phong phú.
  6. powersave: Tổng hợp các script để mở rộng khả năng dùng pin của Linux. Trong trang git của tác giả đã có hướng dẫn khá chi tiết và cụ thể.
2. Tắt card rời đối với card Radeon. Mở file /etc/fstab và gõ đoạn sau:
debugfs /sys/kernel/debug debugfs 0 0
Dùng một trình soạn thảo bất kì để mở file /etc/modprobe.d/blacklist.conf thêm vào cuối file dòng sau:
blacklist radeon
Sau đó mở file /etc/rc.local ở cuối file thêm vào dòng sau:
modprobe radeon
echo OFF > /sys/kernel/debug/vgaswitcheroo/switch
exit 0

Đây là một giải pháp cực kì hiệu quả, giải quyết được vấn đề nóng máy, tốn pin, chạy không ổn định bên Linux. Và nếu không cần đến quá nhiều tài nguyên bên card đồ họa rời, thì đây là 1 thủ thuật rất nên sử dụng. Phương pháp chuyển đổi giữa 2 chế độ card đồ họa được gọi là "Hybrid graphics". Đây là 1 tài liệu rất hay về chủ đề này: link đây. Trong đó có cả cách tắt card ATI và NVIDIA.

3.Các biện pháp khác. - Giảm nguồn sáng của laptop.
- Để làm mát laptop có thể dùng quạt tản nhiệt. Loại từ 100k đến vài triệu tùy vào hầu bao.
- Dùng một trình soạn thảo bất kì mở file /etc/default/grub tìm đến dòng GRUB_CMDLINE_LINUX_DEFAULT và sửa thành:

GRUB_CMDLINE_LINUX_DEFAULT="quiet splash pcie_aspm=force i915.i915_enable_rc6=1 i915.i915_enable_fbc=1"
Sau đó ta gõ lệnh sau để tùy chỉnh lại grub:

sudo grub-mkconfig -o /boot/grub/grub.cfg

- Đối với các sản phẩm của Dell. Vào Ubuntu Software Centre hoặc các package manager đối với các bản Linux khác và search keyword là dell, trong phần technical item cài đăt các gõi hỗ trợ laptop của hãng này. Điển hình có gói i8kutils, aircraft-manager...

- Tắt bluetooth: Mở /etc/rc.local và thêm dòng sau:
rfkill block bluetooth
- Cập nhật thường xuyên các driver của hệ thống. Nâng cấp các phiên bản linux mới để fix các bugs cũng như cải thiện tốc độ.
4. Nguồn tham khảo:

Dec 14, 2012

Hướng dẫn khôi phục GRUB 2 sau khi cài Windows

Thông thường, khi cài Windows trước rồi mới cài Linux thì việc GRUB tự động cấu hình menu boot là chuyện không có gì phải lo lắng. Tuy nhiên, trong một số trường hợp, ta cài Linux trước, cài Windows sau, và dĩ nhiên menu boot bên Windows không nhận diện được Linux :( . Cài mới lại Linux rất tốn công và không đáng để làm vậy [Thực tế nho nhỏ là gần 1 năm mình đã dùng cách ấy].
Tutorial sau sẽ hướng dẫn bạn khôi phục lại GRUB2, đồng thời có thể boot được vào cả 2 HĐH.

Công cụ:
- Hệ điều hành Linux, bản distro mình dùng là Ubuntu.
- 1 cái USB hoặc đĩa cài đặt Ubuntu.

B1. Dùng USB hoặc CD chạy live.
B2. Ctrl + Alt + T hoặc tìm chương trình để mở shell command.
B3. Nhấn lệnh "sudo fdisk -l" để xem danh sách các phân vùng trong ổ đĩa. Đồng thời xác định ổ đĩa chứa Linux.
Như ta thấy trong hình mình họa, đĩa cứng được xác định ở /dev/sda và phân vùng chứa hệ điều hành Linux là /dev/sda2
B4. Gõ lần lượt các lệnh sau:
sudo mount /dev/sdx# /mnt  # x# là phân vùng chứa hđh Linux
sudo mount --bind /dev /mnt/dev
sudo mount --bind /proc /mnt/proc
sudo cp /etc/resolv.conf /mnt/etc/resolv.conf
sudo chroot /mnt
sudo grub-install --recheck /dev/sdx  # x là ổ đĩa cần tạo boot menu
sudo reboot
B5. Rút USB hoặc đĩa CD và vào bản Linux trên máy tính.
B6. Mở terminal và gõ lệnh "sudo update-grub" để cập nhật lại grub.
Vậy là xong, giờ có thể dùng song song 2 hệ điều hành.
Nguồn: http://www.lancelhoff.com/restore-grub2-after-installing-windows/
P/s: Lâu lắm rồi mới viết blog, trình có kém đi một chút

Sep 23, 2012

Tản mạn về C

Bài toán: Viết chương trình tính diện tích một hình tam giác khi biết chiều cao và cạnh đáy.

#include <stdio.h>
int main() {
 float height, base, area;                    /* variables definition */
 /*input data*/
 
 printf(" Hight :");
 scanf("%f", &height);
 printf(" Base :");
 scanf("%f", &base);
 
 /*calculate the area of a triangle*/
 area = 0.5 * ( height * base);
 /*output result */
 printf(" The area of triangle = %f \n", area);
 return 0;
}

Một chương trình C bao gồm rất nhiều module, được gọi là các hàm (function). Một hàm bắt buộc phải có trong chương trình C là main . Các vấn đề về hàm sẽ được đề cập sau.
Trong chương trình này gồm 2 thành phần: chỉ thị tiền xử lý và hàm main. Trong hàm main là tập hợp các câu lệnh và phép toán. Chỉ thị tiền xử lý ( preprocessor) là các lệnh được thực thi trước khi mã nguồn được dịch, nhờ đó, ta có thể thay đổi mã nguồn một cách tự động. Công dụng của preprocessor bao gồm:

  • Gọi các thư viện chuẩn, các file header, ...
  • Định nghĩa các macro
  • Dịch có điều kiện. Ví dụ: Đối với HĐH Linux hệ thống sẽ compile source cách này, nhưng với Win thì lại khác.
  • Định nghĩa lỗi do người dùng xác định
Bàn luận một chút về hàm main . Như đã biết, hoặc giả nếu chưa biết thì bây giờ biết, một hàm trong C thường có cấu trúc sau:
[Kiểu trả về] < tên hàm >([Các đối số])
Dường như với mọi hàm, thì kiểu trả về và tên hàm là các thông số bắt buộc ( các đối số có thể có hoặc không). Tuy nhiên với C, thì hàm main không nhất thiết phải có giá trị trả về. Thực tế, trong C, ta có thể khai báo hàm main theo 4 cách phổ biến sau:

  • void main()
  • int main()
  • void main(int argc, char** argv)
  • int main(int argc, char** argv)
Các được khuyến khích nhất là int main( int argc, char** argv) . Còn vì sao được khuyến khích thì sẽ được chém sau.
Trong một chương trình, thì hàm main chỉ được gọi một và chỉ một lần .
Trong hầu hết các tài liệu thì main là một hàm không thể thiếu. Vậy có khi nào trong chương trình của C không có main? Câu trả lời là có. Đối với các môi trường freestanding ( freestanding environment) thì không bắt buộc phải có main. Khác với freestanding environment, hosted environment yêu cầu phải có hàm main .
Vậy hosted và freestanding environment là cái gì gì? Nó có ăn được không?
Trả lời:

  • Hosted environment là một môi trường không chỉ hỗ trợ đầy đủ cho ngôn ngữ lập trình ( cụ thể ở đây là C), mà còn cung cấp các thư viện chuẩn ( STL - Standard Template Library). Ví dụ: Hệ điều hành Windows, Linux.
  • Freestanding environment là môi trường chỉ đơn thuần hỗ trợ C về ngôn ngữ và trình dịch mà không có các thư viện chuẩn. Ví dụ: Các hệ thống nhúng, di động ...
Hàm printf có chức năng hiển thị ra thiết bị xuất chuẩn ( stdout), ở đây là màn hình, dòng chữ Height: Base: . Hàm scanf có chức năng truyền dữ liệu đầu vào chuẩn ( stdin) theo format định sẵn vào các biến height và base. Các hàm này khá giống hàm Writeln, Readln trong Pascal. Những hàm này cũng rất thú vị, tuy nhiên có lẽ sẽ được đề cập trong I/O stream và các vấn đề xung quanh .

Aug 24, 2012

Oracle VM VirtualBox

Đây là phần mềm tạo máy ảo rất đáng dùng vì các ưu điểm:

  • Dễ sử dụng và cài đặt. Đôi lúc chỉ cần next, next vài cái là có thể tạo xong 1 máy ảo.
  • Gọn nhẹ, bộ cài chỉ mấy tầm 90MB nhưng có thể có đầy đủ các tính năng phổ thông dành cho máy ảo.
  • Miễn phí.

Link download: Click here.

image

Giao diện đơn giản và dễ sử dụng, panel bên trái là danh sách các máy ảo, cũng như tình trạng các máy. Bển phải là thông tin liên quan đến mỗi máy.

Hướng dẫn tạo một máy ảo:

  1. Chọn New: màn hình New Virtual Machine Wizard sẽ hiện ra, nhấn next để tiếp tục.
    image
  2. Name:nhập tên máy ảo, thông thường tên này trùng với HĐH sẽ cài, do vậy chương trình sẽ đoán xem máy ảo này sẽ được cài HĐH nào và tự động thiết lập cấu hình ở OS Type, nếu không thì người dùng có thể tùy chỉnh.
    image
  3. Memory: thiết lập bộ nhớ RAM trên máy ảo, cần phải cẩn thận thiết lập này. Không phải lúc nào recommend của VM Virtual Box cũng đúng, cách tốt nhất là xem yêu cầu cấu hình của HĐH, đồng thời cho thêm vài chục đến vài trăm mb trống để chạy các ứng dụng máy ảo.
    image
  4. Virtual Hard Disk: Tạo ổ cứng ảo. Có 2 tùy chọn:
    • Tạo một đĩa mới: Create new hard disk.
    • Sử dụng đĩa đã có (file có đuôi .vdi…): Use existing hard disk.
    image
  5. Loại đĩa, mặc định là VDI.
    image
  6. Cấp phát ổ đĩa: Có 2 tùy chọn là Dynamically allocated tức là dùng tới đâu cấp phát tới đó, ví dụ ổ đĩa ảo có kích thước là 10GB nhưng chỉ sử dụng 2GB thì trên ổ cứng máy thật file .vdi chứa đĩa ảo này chỉ chiếm 2GB. Tùy chọn này khiến ổ cứng thật rất dễ bị phân mảnh. Tùy chọn nữa là Fixed size, tức là đăng kí ban đầu bao nhiêu thì file .dvi sẽ chiếm chừng đó dung lượng. Giả sử đĩa ảo kích thước 10GB nhưng chỉ dùng có 2GB thì trên ổ cứng thật file .vdi của đĩa ảo này có kích thước 10GB, tùy chọn này khiến ổ cứng ít bị phân mảnh.
  7. Chọn kích thước đĩa ảo. Xong next rồi Create.
    image

 Sử dụng:

  • Các hướng dẫn trong phần mềm này đều nói đến 1 phím là host key, đó là phím Ctrl bên phải.
  • Một số shortcut quan trọng:
    Hostkey + F Chế độ full màn hình
    Hostkey + A Chế độ màn hình tùy chỉnh
    Hostkey + R Restart máy ảo
    Hostkey + Q Close máy ảo
    Hostkey Chuyển đổi con trỏ chuột giữa máy ảo và máy thật
  • Lần đầu tiên cài đặt, chương trình sẽ yêu cầu đĩa boot (đúng hơn là media …). Chỉ cần trỏ tới file iso, hoặc đĩa cài đặt OS là có thể sử dụng được.
  • Thông thường, mỗi khi làm việc xong trên máy ảo, chương trình sẽ tự động lưu trạng thái cuối cùng của máy. Tuy nhiên, nếu muốn lưu và load lại cái phiên thay đổi trước đó, thì chương trình sử dụng tính năng Snapshot, tính năng này yêu cầu cài đặt Guest Addition (Menu-> Device-> Install Guest Addition). Với mối HĐH khác nhau sẽ có cách cài đặt khác nhau.
    Tham khảo cách dùng Snapshot bên win: http://forum.bkav.com.vn/showthread.php?28810-Huong-dan-tao-may-ao-bang-VirtualBox-Complete-

Jul 16, 2012

Hướng dẫn cài đặt Qt library trên Visual Studio 2010.

Lưu ý: Cài đặt hoặc nâng cấp Visual Studio 2010 lên Service Pack

Download và giải nén source code của Qt: Link download. Đối với các bản trên 4.8 cần cài đặt Perl.

Giả sử giải nén và chép sang thư mục: C:\QtFw

Cài đặt biến môi trường. Dùng cmd:

QTDIR = C:\QtFw
QMAKESPEC = win32-msvc2010
Code cmd:
Setx QTDIR C:\QtFw
Setx  QMAKESPEC  win32-msvc2010

Thêm C:\QtFw\bin vào biến PATH (Trong System Properties--Advanced--Enviroment Variables ).

Để sử cài đặt Qt cho x86 ( ngay cả khi dùng win 64bit nhưng tạo ứng dụng x86 thì vẫn phải xài bản này): Mở Visual Studio Command Prompt. Đối với 64bit Qt library - để xây dựng các ứng dụng 64bit: Mở Visual Studio x64 Win64 Command Prompt.

Gõ lệnh sau

Cd C:\QtFw
Configure -platform win32-msvc2010 -debug-and-release -no-webkit -no-phonon -no-phonon-backend -no-script -no-scripttools -no-multimedia -no-qt3support -fast
Nmake.

Ngồi đợi …

Download và cài đặt Qt Visual Studio Add-in.

Trong menu Qt trong VS2010. Qt < Qt Options < Qt Versions < Add.

Sau đó có thể create 1 project Qt trong VS2010 giống như tạo một project thông thường.

Cách này chỉ hiệu quả cho bản thương mại của VS2010, còn bản Express không cài Qt Visual Studio Add-in được nên có cách khác. Sẽ được post sau.

Jun 18, 2012

[Hỏi ngu]: Sự khác nhau giữa Null pointer và void pointer


Tập hợp những câu hỏi mà đôi lúc mình ngộ ra là mình đã hỏi rất ngu =)) .
Null pointer là một giá trị của con trỏ. Con trỏ có nhiều kiểu (int*, char*) và mỗi kiểu đó sẽ qui định giá trị null khác nhau: NULL có thể là 0, cũng có thể là '\0' …
Void pointer là một kiểu - kiểu void* - con trỏ này có thể trỏ đến bất kì kiểu nào.
Vậy nên: Null pointer là một giá trị, còn void pointer là một kiểu con trỏ:
Example:
Void *pa = NULL;
Một tham khảo khác:
Thông thường một null pointer trỏ đến:
  • Địa chỉ 0.
  • Trỏ đến địa chỉ không hợp lệ  cho người dùng truy cập ( như địa chỉ 0x00000000 …), nếu cố truy cập dữ liệu vào địa chỉ này sẽ gây ra lỗi.

Jun 1, 2012

Hướng dẫn compile trên partition của Win trên Linux.

Đang mày mò thằng Ubuntu thì gặp một vấn đề vô cùng khó chịu đó là không thực thi được những file đã compile được trên ổ đĩa Win (Ubuntu mount vô). Sau một hồi tìm hiểu thì mình đã hiểu ra vấn đề: permission của đĩa.
Dùng lệnh sau:
gksu gedit /etc/fstab
File này chứa danh sách tất cả các partition mà người dùng muốn mount, mỗi dòng là một partition (dấu "#" đầu dòng báo hiệu dongf đó là chú thích - comments). Đừng thay đổi, xóa các dòng đã được ghi sẵn trên file.
  1. Tìm thông tin về partitions, bao gồm: địa chỉ partition, UUID, nhãn. Gõ lệnh sau:
    sudo blkid -c /dev/null
    dòng lệnh này sẽ hiện các thông tin về partitions. 
  2. Tạo các thư mục chứa các partition:
    sudo mkdir /media/Data
  3. Chọn tiêu chuẩn tập tin (NTFS): ở đây là "ntfs-3g".
  4. Các tùy chỉnh khác:


    • uid=#### chỉ định userid nào sẽ kiểm soát tập tin trên phân vùng đó. Ví dụ: "uid = 1000" nghĩa là userid = 1000 sẽ kiểm soát các tập tin. Để tìm UID của user dùng lệnh sau: "echo $UID"
    • gid=#### chỉ định ID nhóm (groupid) sẽ kiểm soát các file trên phân vùng đó. Khái niệm tương tự userid. Để tìm các goupid dùng lệnh sau: "cat /etc/group". Thông thường nếu không muốn phiền toái thì UID = GID.
    • umask=UGO [Quan trọng] . Mỗi chữ cái tương ứng với các số từ 0 đến 7 - chỉ định permission (quyền truy cập). Các số này trái ngược với các thông số thông thường. Trong thiết lập thông thường 7 nghĩa là "đọc, viết, thực thi" thì trong fstab có nghĩa là "không có đặc quyền nào". U = quyền cho user, G = quyền cho nhóm, O = quyền cho other. Ví dụ: umask = 000 nghĩa là mọi người đều có quyền truy cập và chỉnh sửa partition.


Cấu trúc trong fstab( trong dấu [] nghĩa là tùy chọn): ["LABEL=Windows" | "UUID=ABCDEFGHIJKLKLMNOP"]  <Địa chỉ partition>  <Địa chỉ thư mục lưu partiotion được mount> ntfs-3g defaults, <uid = ####> , <gid = ####>, <umask = UGO> 0 0 Ví dụ:  /dev/sdb5 /mnt/Music ntfs-3g defaults,uid=1002,gid=1500,umask=227,dmask=022,fmask=133 0 0
    UUID=ABCDEFGHIJKLKLMNOP /media/Windows ntfs-3g defaults,auto,uid=1000,gid=1000,umask=002 0 0 Khởi động lại máy rồi gõ lễnh "sudo mount -a" là có thể excute các file compile. Update: Sử dụng gói ntfs-config
    Click chọn vào phân vùng dùng để compile code. Sau đó tick vào mục Enable Write Support for internal device. Nếu muốn chắc chắn thì tick vào cả 2 mục đều được.

    May 12, 2012

    Danh sách liên kết (Linked List)

    Ngộ nhận ra bài này mình viết code rất dở, để khi nào rảnh sẽ edit lại. Danh sách liên kết có những ứng dụng rất thú vị

    Hôm nay Kỹ Thuật Lập Trình được học danh sách liên kết, vì ở dưới chăm chú sửa cái code thực hành mà không bắt kịp vấn đề, dù những định nghĩa căn bản đều hiểu. Cần phải tìm hiểu nó một cách cụ thể.

    1.Khái niệm: Danh sách liên kết (linked list) là một cấu trúc dữ liệu bao gồm một nhóm các nút (nodes) tao thành một chuỗi.  Thông thường mỗi nút gồm dữ liệu (data) ở nút đó và tham chiếu (reference) đến nút kế tiếp trong chuỗi.
    Danh sách liên kết là một trong những cấu trúc dữ liệu đơn giản và phổ biến nhất.
    (Nguồn: Wikipedia)
    clip_image001
    Ưu điểm:
    • Cung cấp giải pháp để chứa cấu trúc dữ liệu tuyến tính.
    • Dễ dàng thêm hoặc xóa các phần tử trong danh sách mà không cần phải cấp phát hoặc tổ chức lại trật tự của mảng.
    • Cấp phát bộ nhớ động
    Nhược điểm:
    • Một danh sách liên kết đơn giản không cho phép truy cập ngẫu nhiên dữ liệu.
    • Chính vì lí do trên mà một số phép tính như tìm phần tử cuối cùng, xóa phần tử ngẫu nhiên hay chèn thêm, tìm kiếm có thể phải duyệt tất cả các phần tử.
    Phân loại:
    • Danh sách tuyến tính (Linear list):
    clip_image002
    • Danh sách vòng (circular list):
    clip_image003
    • Danh sách liên kết đôi (Double list):
    clip_image004
    Cấu trúc:
    clip_image005
    Data: Thành phần chứa một hay nhiều biến dữ liệu.
    Next ptr: Tham chiếu trỏ đến phần tử kế tiếp trong cấu trúc.
    Head: biến tham chiếu trỏ đến phần tử đầu tiên của danh sách.
    clip_image006

    Struct LLnode {
    DataType Data;
    LLnode* next;
    };
     
    2.Các phép toán:
    Cho cấu trúc đơn giản:
    struct LLintNode {
    int Data;
    struct LLintNode* Next;
    };
    Đếm số phần tử của Linked List:
    Duyệt từng phần tử rồi đếm, cho đến khi nào gặp phần tử cuối.


    int LengthLL(LLNode* head) {
    int length = 0;
    while (head != NULL) {
    ++length;
    head = head ->Next;
    }
    return length;
    }
    Thêm một phần tử vào cuối linked list:
    Nếu danh sách rỗng, thêm nút vào head.
    Ngược lại, tìm phần tử cuối cùng của danh sách rồi thêm nút mới vào Next của nút cuối cùng đó:


    void AddLast(LLNode** head, int data) {
    LLNode** tmp = head;
     
    LLNode* NewNode;
    NewNode = (LLNode*) malloc(sizeof(LLNode));
    NewNode->Data = data;
    NewNode->Next = NULL;
     
    if ((*tmp) == NULL) {
    (*tmp) = NewNode;
    } else {
    while ((*tmp)->Next !=NULL) {
    tmp = &((*tmp)->Next);
    }
    (*tmp)->Next = NewNode;
    }
    }
     
    Xóa phần tử cuối cùng:
    Tìm phần tử cuối cùng của danh sách, rồi gán bằng NULL.


    void RemoveLast(LLNode** head) {
        LLNode** tmp = head;
        if ((*tmp) !=NULL) {
            while ((*tmp)->Next != NULL) {
                tmp = &((*tmp)->Next);
            }
        }
        (*tmp) = NULL;
     
    }
    Thêm phần tử vào đầu danh sách:
    clip_image007




    void AddFirst(LLNode** head, int Data) {
        LLNode** tmp = head;
        LLNode* NewNode;
        
        NewNode = (LLNode*) malloc(sizeof(LLNode));
        NewNode->Data = Data;
        NewNode->Next = (*head);
        
        (*tmp) = NewNode;
     
    }
    Xóa phần tử đầu tiên:
    Nếu danh sách khác rỗng, đưa phần tử Next lên phía trước.


    void RemoveFirst(LLNode** head) {
        LLNode** tmp = head;
        if ((*tmp) != NULL) {
            (*tmp) = (*tmp)->Next;
        }
    }
    Tìm kiếm phần tử trong danh sách:


    LLNode* FindNode(LLNode** head,LLNode* src) {
        LLNode** tmp = head;
        while ( src->Data != (*tmp)->Data) {
            tmp = &((*tmp)->Next);
        }
        return (*tmp);
     
    }
    Chèn thêm 1 phần tử sau phần tử currrent:


    int InsertNode(LLNode** head, LLNode* current, LLNode* NewNode) {
        LLNode** tmp = head;
        while ((current != (*tmp)) && (*tmp != NULL)) {
            tmp = &((*tmp)->Next);
        }
        
        if (*tmp == NULL) {
            return 0;
        } else {
            NewNode->Next= current->Next;
            current->Next = NewNode;
            
            (*tmp) = current;
            return 1;
        }
            
     
    }
    Xóa phần tử bất kì biết trước dữ liệu:

    int RemoveNode(LLNode** head, LLNode* current) {
        LLNode** tmp = head;
        while ((current != (*tmp)) && (*tmp != NULL)) {
            tmp = &((*tmp)->Next);
        }
        if (*tmp == NULL) {
            return 0;
        } else {
            (*tmp) = (*tmp)->Next;
            return 1;
        }
    }
    3.Tham khảo:

    May 3, 2012

    Vẽ các hình học cơ bản trong OpenGL.


    Tạo một dự án Empty Project và thiết lập cài đặt dành cho glut và OpenGL. Có thể tham khảo tại đây.
    Gõ (hoặc chép) đoạn code sau:
    #include <iostream>
    #include <gl\glut.h>
    #include <gl\GL.h>
    #include <gl\GLU.h>
     
    void display() {
     
        glColor3f(1.0,1.0,0.0);
     
        glPointSize(10);
        glBegin(GL_POINTS);
            glVertex2f(50,100);
            glVertex2f(200,200);
        glEnd();
        glFlush();
    }
    int main(int argc, char** argv) {
        glutInit(&argc,argv);
        
     
        glutInitDisplayMode(GLUT_RGB|GLUT_SINGLE);
        glutInitWindowPosition(0,0);
        glutInitWindowSize(500,500);
        glutCreateWindow("Ve");
        
        glClearColor(0.0,0.0,0.0,0.0);
        glClear(GL_COLOR_BUFFER_BIT);
     
        glOrtho(0.0,500,0.0,500,-1.0,1.0);
     
        glutDisplayFunc(display);
        glutMainLoop();
        return 0;
    }

    Phần #include: để nhập các thư viện, file header để sử dụng các hàm glut, OpenGL.

    Nghiên cứu các hàm được gọi trong Main() trước:


    • glutInit(int* pargc,char **argv): Khởi tạo thông số cho cửa sổ của glut. Các tham số pargc và argv được lấy từ hàm main().
    • Các hàm về thiết lập cửa sổ màn hình:

      • glutInitDisplayMode(int mode): thiết lập chế độ màu, buffer cho màn hình.

    Danh sách các thiết lập:

    GLUT_RGBA: thiết lâp cho chế độ màn hình RGBA.

    GLUT_RGB: tương tự GLUT_RGBA.

    GLUT_INDEX: thiết lập chế độ màu mặc định.

    GLUT_SINGLE: thiết lập chế độ màn hình buffer đơn.

    GLUT_DOUBLE: thiết lập chế độ màn hình buffer đôi.

    GLUT_ACCUM: thiết lập chế độ accumulation buffer.

    GLUT_ALPHA: thiết lập chế độ đối tương anpha cho buffer màu.

    GLUT_DEPTH: thiết lập cho depth buffer.

    GLUT_STENCIL: thiết lập cho stencil buffer.

    GLUT_MULTISAMPLE: thiết lập cho multisampling.

    GLUT_STEREO: thiết lập chế độ stereo.

    GLUT_LUMINANCE: thiết lập cho chế độ màu "luminance".

    Sử dụng toán tử OR để kết hợp các chế độ màu, buffer với nhau.


    • glutInitWindowPosition(int x, int y): tọa độ cửa sổ màn hình.
    • glutInitWindowSize(int x, int y): thiết lập kích thước cửa sổ màn hình.
    • glutCreateWindow(char* title): tạo cửa sổ màn hình với tiêu đề là title.


    • glClearColor(Glclampf red, Glclampf green, Glclampf blue, Glclampf alpha): thiết lập chế độ màu mới cho toàn bộ ứng dụng.
    • glClear(int mode): GL_COLOR_BUFFER_BIT: thông số để thiết lập cho màu sắc. Còn một số thiết lập nữa sẽ được đề cập sau.
    • glOrtho(...): thiết lập tầm nhìn trực giao, sẽ được nói chi tiết trong bài về phép biến trong OpenGL.


    • glutDisplayFunc(void (*f)(void)): gọi hàm để thực hiện việc vẽ khi cửa sổ màn hình hiển thị. Trong ví dụ này là gọi hàm display.
    • glutMainLoop(): Lặp đi lặp lại các hàm callback - sẽ đề cập sau - đến khi nao cửa sổ đóng lại.

    Trong hàm display:


    • glColor3f( red, green, blue ): thiết lập màu sắc cho đối tượng sắp vẽ.
    • glPointSize(float size): kích thước điểm ảnh.
    • glBegin(int mode): gồm các thông số và minh họa phía dưới:

    clip_image001


    • glEnd():kết thúc quá trình vẽ.
    • glFlush(): đưa dữ liệu từ bộ nhớ tạm và màn hình.