C++ Passing argument (by value vs by references)

การส่ง argument ไปยังฟังก์ชั่น มี 2 แบบ คือ

  • pass by value คือการ คัดลอกค่า ที่เก็บจากตัวแปรที่ส่ง ไปยังตัวแปรของฟังก์ชั่น
  • pass by reference คือ การใช้งาน ข้อมูลที่เก็บจาก address ของตัวแปรที่ส่งไป ในฟังก์ชั่นนั้น

ตัวอย่างการเขียนฟังก์ชั่น แบบ pass by value

#include <iostream>
using namespace std;

void increment(int inp){
  cout << inp++ << endl;
}

int main(){
 for(int i=0;i<5;i++)
  incrment(i);
 return 0;
}

เอาท์พุตของโปรแกรม

0 1 2 3 4

ตัวอย่างการเขียนฟังก์ชั่นแบบ pass by reference

#include <iostream>
using namespace std;

void increment(int &inp){
  cout << inp++ << endl;
}

int main(){
 for(int i=0;i<5;i++)
  increment(i);
 return 0;
}

เอาท์พุตของโปรแกรม

0 2 4

วิธีการส่งค่าแบบแรกนั้นจะใช้เวลามากกว่า เนื่องจากจะต้องมีโอเปอเรชั่นในการคัดลอกค่าเพิ่มเติม ซึ่งถ้าต้องการส่งไฟล์ข้อมูลโครงสร้างขนาดใหญ่แล้ว แน่นอนว่าประสิทธิภาพย่อมลดลงแน่นอน แต่การส่งแบบ pass by reference นั้นก็เสี่ยงต่อการที่จะมีการเปลี่ยนแปลงค่าเช่นเดียวกัน

 

วิธีการคัดลอก vector ของ c++ แบบง่าย ๆ

สมมติว่ามี vector ตัวหนึ่งที่ต้องการคัดลอก สามารถทำได้ง่าย ๆ คือ ตั้งชื่อของตัวแปรขึ้นมาแล้ว ใช้โอเปอเรเตอร์ = ในการคัดลอกดังตัวอย่างบรรทัดที่ 4

vector<int> a ;
for(int i=0; i< 10 ;i++)
 a[i] = 10-i;
vector<int> b = a;
for(int i=0; i < 5;  i--)
 a.pop_back();

ในที่นี้ผลลัพธ์ของ a และ b ที่ได้จะแตกต่างกันดังนี้

a={10,9,8,7,6}
b={10,9,8,7,6,5,4,3,2,1}

เพราะโดยหลักแล้วการสร้างตัวแปรถ้าไม่ใช่ตัวแปรพื้นฐาน การใช้เครื่องหมาย = จะถือเป็นการ copy by value นั่นเอง

การแจ้งเตือนค่าขอบเขต ของการดำเนินการทางคณิตศาสตร์ ของคอมไพลเลอร์ C++(GCC)

วันนี้ผมจะพูดถึงข้อจำกัดในการคำนวณในทางคณิตศาสตร์เวลาที่เราเขียนโปรแกรม โดยยกสองตัวอย่างนี้ขึ้นมา

  • 1/0
  • sqrt(-1)

เวลาที่เขียนโปรแกรมในลักษณะ อินพุตจากผู้ใช้ หรือจากไฟล์ ควรมีการตรวจสอบค่าเหล่านี้ด้วย เนื่องจากอาจจะทำให้การทำงานของโปรแกรมมีการผิดพลาดได้ โยงกลับมาที่ภาษา C++ นะครับ ถ้าเขียนแบบนี้ลงไปตรงๆ

cout << 1/0  ;

คอมไพล์เลอร์จะแจ้งเตือนว่า division by zero (หมายถึงหารด้วย 0) เช่นตัวนี้ผมคอมไพล์บนวินโดวส์โดยใช้ GCC 4.9.2 มันจะแจ้งเตือนเป็นข้อความว่า

97 11 C:\Users\user\Desktop\OR_Solver\main.cpp [Warning] division by zero [-Wdiv-by-zero]

หมายถึงบรรทัดที่ 97 คอลัมน์ที่ 11 มีการหารด้วย 0

ซึ่งการแจ้งเตือนของมันคือคอมไพล์ผ่านนะครับ แต่ว่าเวลารันโปรแกรมจะตายทันที(ทั้งนี้แล้วแต่คอมไพลเลอร์หรือ IDE ที่ใช้นะครับ)

คราวนี้ลองเป็นลักษณะอินพุตจากผู้ใช้บ้าง จากตัวอย่างต่อไปนี้ครับ

int input1 ,input2 ;
cout << “Input 1 : ” ;
cin >> input1;
cout << “Input 2 : ” ;
cin >> input2;
cout << input1/input2 << endl;

ตรงนี้เวลาคอมไพล์ ตัว compiler จะไม่รู้กับเราว่าอาจจะมี การหารด้วย 0 เกิดขึ้น ซึ่งมันจะไม่เตือนให้เราทราบใดๆ เลยครับ(คอมไพล์ผ่านฉลุย)

ตัวอย่างการรันเมื่อ เลขตัวที่ 2 เป็น 0 นะครับ

Input 1 : 2
Input 2 : 0
inf

จะเห็นว่ามันจะออกมาเป็นค่า inf หรือ infinity ซึ่งหมายถึงเลขที่มีค่าเป็นอนันต์(ไม่มีที่สิ้นสุด) ครับ

คราวนี้ลองมาดูการถอดแสควร์รูทของตัวเลขติดลบบ้างว่าคอมไพล์เลอร์มันว่ายังไง

cout << sqrt(-1) << endl;

ตัวนี้คอมไพล์ผ่าน แต่ไม่แจ้งเตือนใดๆ  ทดลองรันดูเอาท์พุตเป็นค่านี้ครับ

nan

คำว่า nan ในที่นี้หมายถึง Not A Number ครับ ถ้าเป็นคณิตศาสตร์ รากที่ 2 ของค่าลบจะเป็นจำนวนจินตภาพ ซึ่งผมขอนำโครงสร้างของจำนวนจริงมาแปะไว้ให้ดูเผื่อใครไม่รู้จำนวนจินตภาพคืออะไร สนใจคณิตศาสตร์เพิ่มเติมก็ตามลิงค์ไปเลยนะครับ วันนี้ขอจบเพียงเท่านี้ก่อน 😀

เครดิตภาพ : http://vichakarn.triamudom.ac.th/comtech/studentproject/final54/824/Infinite%20Stratos/MATH/Real.html

การปรับแต่งเครื่องมือ editplus ใช้งานร่วมกับคอมไพลเลอร์ gcc

สำหรับท่านที่ใช้โปรแกรม editplus แล้วต้องการให้สามารถคอมไพล์และรันโปรแกรมภาษาซีได้ ต้องอ่านบทความนี้ครับ

ก่อนอื่นขอให้ท่านผู้อ่านติดตั้งโปรแกรม editplus (โค๊ดอีดิเตอร์) และ MinGW (คอมไพลเลอร์ภาษาซี) จากนั้นเปิดโปรแกรม editplus ขึ้นมาครับ

ไปที่ เมนู Tool -> Configure User Tools จะปรากฏไดอะล็อกจัดการเครื่องมือสำหรับผู้ใช้

ให้เปลี่ยนชื่อกลุ่มเครื่องมือดังต่อไปนี้ (คลิ๊กที่รูปเพื่อดูภาพขยาย)

Editplus_GCC2

จากนั้นให้เพิ่มโปรแกรม gcc เป็น compiler ดังรูป

Editplus_GCC3

อ่านเพิ่ม

ภาษา C: การเขียนโปรแกรมเพื่อเรียกใช้โปรแกรมภายนอก

ท่านผู้อ่านครับ  บางครั้งบางคราเราต้องการใช้งานโปรแกรมของชาวบ้านที่แจกให้ใช้ฟรีมารวมกับโปรแกรมของเรา  ถ้าเผอิญชาติที่แล้วเราทำบุญมามาก เราก็จะพบว่าโปรแกรมมีไลบราลีให้เรียกใช้ แต่ถ้าบุญวาสนาเราไม่ถึงก็จะเจอแค่ไฟล์ที่เป็น  binary มา แล้วทีนี้จะทำอย่างไรกันดีล่ะครับ

โชคดีที่ในภาษา C มี ฟังก์ชัน system และ popen เพื่อจัดการปัญหาเหล่านี้ได้ เสียดายอย่างเดียวที่ไม่อยู่ใน standard library (ISO/ANSI C)  แต่จะเป็นมาตรฐาน POSIX ซึ่งผู้นำไปใช้ก็จะต้องเจอความเสี่ยงเนื่องจาก มาตรฐานของ POSIX จะขึ้นอยู่กับระบบปฏิบัติการด้วย ครับ

ฟังก์ชั่น system

ฟังก์ชั่นนี้ ใช้สำหรับเรียกโปรแกรมอื่น ซึ่งเราจะระบุคำสั่งที่ใช้งานเป็นสตริงของคำสั่ง  ซึ่งเมื่อเราเรียกใช้คำสั่งนี้แล้ว ระบบจะทำการเรียกคำสั่งดังกล่าวให้แทน
รูปแบบฟังก์ชั่น

#include <stdlib.h>

int system(const char *command);

ตัวอย่างโปรแกรม

//ไฟล์ Hello.c
void main(){
printf(“This is an output from Hello.c\n”);
}

คอมไพล์เป็นไฟล์ binary ชื่อ hello_out  ด้วย gcc

gcc -o hello_out  Hello.c

//ไฟล์ Call_Hello.c
#include <stdlib.h>

void main(){
printf(“This is an output from Call_Hello.c\n”);
system(“./hello_out”) ;
}

คอมไพล์เป็นไฟล์ binary ชื่อ callHello  ด้วย gcc

gcc -o Call_Hello  Call_Hello.c

ผลลัพธ์จากการรันโปรแกรม  Call_Hello

./Call_Hello
This is an output from Call_Hello.c
This is an output from Hello.c

ฟังก์ชั่น  popen

ในกรณีที่เราต้องการผลลัพธ์ของการทำงานของโปรแกรมภายนอกที่เราเรียกมาใช้งานในโปรแกรม คำสั่ง system นั้นไม่สามารถให้ผลลัพธ์ดังกล่าวได้โดยตรง  แต่ก็มีวิธีการอยู่ เช่น สร้างเอาท์พุตไฟล์ไว้แล้วให้โปรแกรมเราไปเรียกใช้งาน อย่างไรก็ตาม เนื่องจากการควบคุมไม่ได้อยู่ในโปรแกรมเองทำให้อาจเกิดปัญหาได้ เช่นกรณีของการเขียนเอาท์พุตที่ยังไม่เสร็จแล้วโปรแกรมไปเรียกใช้งาน เป็นต้น

ในกรณีแบบนี้เราสามารถใช้ฟังก์ชั่น popen  เพื่อแก้ปัญหาดังกล่าว โดย popen เป็นฟังก์ชั่นในการสร้าง pipe ระหว่างโปรแกรมของเรากับโปรแกรมภายนอก ซึ่งผลลัพธ์ที่เกิดจากการใช้ฟังก์ชั่นนี้ จะได้ file pointer ชี้ไปยังตำแหน่งแรกของหน่วยความจำที่เก็บผลลัพธ์เอาไว้  ซึ่งเราสามารถนำมาใช้ในตัวโปรแกรมของเราได้

รูปแบบฟังก์ชั่น
#include <stdio.h>

FILE *popen(const char *command, const char *type); //เปิด stream  output ของคำสั่ง

int pclose(FILE *stream);  // ปิด stream

ตัวอย่างโปรแกรม
//feching.c
#include <stdio.h>

int main(){
     char *cmd = “./Call_Hello”;
     FILE *inpipe = popen(cmd,”r”);
     char inbuff[1000];
     int line=0;

    printf(“Fetching output from Call_Hello.c\n”);
    while(fgets(inbuff,sizeof(inbuff), inpipe)){
       printf(“line  %d:  %s  \nend”, ++line,inbuff);
   }
   pclose(inpipe);
    printf(“End feching output\n”);
   return 0;
}

คอมไพล์เป็นไฟล์ binary ชื่อ callHello  ด้วย gcc

gcc -o fetching  fetching.c

ผลลัพธ์จากการรันคำสั่ง
./fetching 

Fetching output from Call_Hello.c
line 1: This is an output from Call_Hello.c
line 2: This is an output from Hello.c
End feching output