Lập trình C trong vi điều khiển (Phần 2)

0
6823

Lệnh điều khiển IF…ELSE

if (Điều kiện )
{
   ...
   các câu lệnh;//nếu điều kiện đúng
}
else
{
   ...
   các câu lệnh; //điều kiện sai
}
2018-10-01_215454

Lệnh điều khiển SWITCH… CASE

switch(gia tri ma ban can kiem tra){
case 1:
//  thuc thi doan code nao do
break;
case 2:
// thuc thi
break;
}
2018-10-01_220343.jpg

Nếu không có break thì chương trình thực hiện hết lệnh trong case 1 thì sẽ chạy tiếp các lệnh trong case 2.

Lệnh điều khiển While

Cú pháp

while (Điều kiện )
{
các câu lệnh;//nếu điều kiện đúng
}
do
{
   ...
   các câu lệnh;//nếu điều kiện đúng
}while(điều kiện);

Ví dụ:

#include<stdio.h>
int main(){
   int a=4;
   while(a<10){
   printf("gia tri cua a la: %d\n",a);
   a++;
}
  return 0;
}

Kết quả:

1.jpg

Lệnh điều khiển FOR

Cú pháp

for ( khoi_tao_bien; dieu_kien; tang/giam )
{
   cac_lenh;
}
Lệnh vòng lặp for

Lệnh for thực hiện khi đúng điều kiện, ở ví dụ này ta có thể hiểu:

    n=0 là giá trị đầu của vòng lặp for 

    n<10 là điều kiện kết thúc, 

    n++ mỗi lần vòng lặp chạy sẽ tăng lên 1 đơn vị.

Số vòng lặp của for phụ thuộc vào 3 yếu tố trên.
Nếu các bạn sử dụng vòng phải đảm bảo được chương trình không thực hiện gì ngoài vòng lặp vì khi vòng lặp chạy nó không thể thực hiện các lệnh khác.
Điều kiện của vòng lặp phải chắc chắn sẽ có một lúc nào đó chương trình kết thúc nếu không sẽ bị treo, chương trình không lối thoát.

Ví dụ:

2018-10-01_222437.jpg

Kết quả:

2018-10-01_222035

Lệnh Break, continue, goto

  1. Break;

Thoát khỏi vòng lặp for,while (vòng lặp chứa nó ).

VD:

2018-10-01_223447.jpg

===> Kết quả là chỉ in các giá trị a=4,5,6

2. Continue

Lệnh continue là lệnh mà khi gặp nó thì chương trình sẽ bỏ qua những câu lệnh phía dưới nó(trong cùng 1 câu lệnh lặp) để thực hiện 1 vòng lặp mới.

2018-10-01_225650
2018-10-01_225427.jpg

Như các bạn thấy, vòng lặp này vẫn thực hiện đủ 4 bước. Nhưng kết quả chỉ in ra được:

1 2 3 4

Và sau đó, vòng lặp này lặp vô hạn vì biến i sẽ không bao giờ được tăng lên nữa sau khi câu lệnh if được thực thi, vì bước (4) đặt trong vòng lặp while được coi như thuộc bước (3) của vòng lặp for. Do đó, khi gặp từ khóa continue, bước 4 của vòng lặp while cũng bị bỏ qua luôn, mà dòng lệnh i++ sẽ không bao giờ được thực thi nữa.

Vì thế mà chúng ta thường xuyên sử dụng vòng lặp for hơn, và cũng thường đặt từ khóa continue trong vòng lặp for hơn.

3. goto

Nhảy đến nhãn.(lệnh này không nên dùng)

Lệnh return exit

Hàm ExitHàm exit() trong C/C++ được sử dụng để thoát khỏi chương trình. Hàm này, khi được triệu gọi sẽ ngay lập tức kết thúc chương trình và chuyển quyền điều khiển cho hệ điều hành.              Cú pháp:                                    exit (int  mã_trả_về);mã_trả_về thường là số 0. Số 0 sẽ xác định việc kết thúc chương trình một cách bình thường. Tuy nhiên có một vài trường hợp mã_trả_về là những số khác 0 để xác định một vài loại lỗi.

Hàm return

– Một hàm trả dòng điều khiển về nơi gọi nó bằng câu lệnh return. Khi lệnh return được theo sau bởi một biểu thức thì biểu thức đó sẽ được đánh giá và giá trị này sẽ được trả về cho nơi đã gọi hàm. Khi return đươc gọi mà không có biểu thức đi kèm thì giá trị trả về là không xác định (Thoát khỏi cái hàm nó được gọi và trả về 1 kết quả (Nếu có) .)

Truyền tham trị, tham biến

1.Truyền tham trị

#include
#include
void swapNumber(int a,int b){
int temp=a;
a=b;
b=temp;
}
main(){
int x=3,y=5;
swapNumber(x,y);
printf("%d %d\n",x,y);
system("pause");
}

Khi truyền đối số kiểu tham trị, chương trình biên dịch sẽ copy giá trị của đối số để gán cho tham số của hàm (không tác động trực tiếp đến biến số truyền vào).

Sau khi thực thi, ta thấy giá trị của x à y vẫn như ban đầu (nghĩa là không hoán đổi). Lý do đơn giản là vì khi truyền tham số, sẽ chỉ truyền giá trị của nó hay nói nôm na là truyền bản photocopy. Do vậy, trong hàm nếu có thay đổi giá trị các bản photocopy này thì bản gốc (tức giá trị của biến ban đầu) vẫn không đụng đậy gì.

⇒ Cách này không thể sử dụng được (cho bài toán hoán đổi giá trị).

2. Truyền tham biến

Phương pháp truyền tham biến là cách truyền địa chỉ của đối số cho các tham số tương ứng của hàm được gọi. Với cách truyền tham biến, giá trị của đối số truyền vào có thể bị thay đổi bởi việc gọi hàm.
Truyền tham biến chia ra thành 2 loại : truyền con trỏ (dùng trong C và C++) , truyền tham chiếu (chỉ dùng trong C++)

#include
#include
void swapNumber(int &a,int &b){
int temp=a;
a=b;
b=temp;
}
main(){
int x=3,y=5;
swapNumber(x,y);
printf("%d %d\n",x,y);
system("pause");
}

Hàm swapNumber() cũng làm nhiệm vụ hoán đổi vị trí giữa 2 biến nguyên truyền vào. 
+ Biến tham chiếu không được cấp phát bộ nhớ, không có địa chỉ riêng.
+ Nó dùng làm bí danh cho một biến (kiểu giá trị) nào đó và nó sử dụng vùng nhớ của biến này.
Trong hàm swapNumber(), chương trình sẽ thực hiện lệnh gán sau:
int &a = x;
int &b = y;
a,b ở đây là bí danh của biến x,y. Tức là biến a,b sẽ dùng chung vùng nhớ với biến số x,y.
Các cậu lệnh được thao tác trên biến a,b hay cũng chính là thao tác trên biến x,y. Do vậy, hàm swapNumber() sẽ thay đổi giá trị của đối số truyền vào.

3. Truyền con trỏ

#include
#include
void swapNumber(int *a,int *b){
int temp=*a;
*a=*b;
*b=temp;
}
main(){
int x=3,y=5;
swapNumber(&x,&y);
printf("%d %d\n",x,y);
system("pause");
}

Hàm swapNumber() làm nhiệm vụ đổi chỗ 2 biến nguyên x,y truyền vào. Đối số truyền vào ở đây là địa chỉ 2 biến x,y (&x , &y). Trong hàm swapNumber(), biến con trỏ a,b sẽ trỏ tới địa chỉ của biến x,y (a = &x, b = &y). Và *a và *b chính là giá trị của 2 biến x,y.

Hàm

Cấu trúc hàm

KieuTraVe TenHam(Cac tham so)
{
Các câu lệnh;
}

– Hàm không có giá trị trả về: thì khai báo kiểu tra về là void– Hàm có kiểu trả về : thì khai báo là int, float, double,…Cách gọi hàm

TenHam( Các tham số);  // đối với hàm không có giá trị trả về

Kiểu dữ liệu TênBiến =TenHam( Các tham số); // đối vói hàm có giá trị trả về

VD:

#include 
intmax2(inta, intb) 
{
returna > b ? a : b;
}
intmax3(inta, intb, intc) 
{
returnmax2( max2(a, b), c);
}
intmain()
{
inta = 7, b = 13, c = 4;
printf("So lon nhat la %d \n", max3(a, b, c));
return0;
}

Ở ví dụ này chúng ta xây dựng 2 hàm để tìm số lớn nhất của 2 số và 3 số. Trong hàm max2 chúng ta sử dụng toán tử diều kiện để tìm số lớn nhất trong 2 số. Trong hàm max3 ta đã gọi hàm max2 đến 2 lần để tìm số lớn nhất trong a, b rồi lấy số tìm được só sánh với c tìm ra số lớn nhất.Chú ý: Hàm khai báo sau được gọi các hàm đã khai báo trước nó nhưng các hàm khai báo trước không được gọi hàm khai báo sau. Tức là trong VD trên nếu ta xây dựng hàm max2 ở sau hàm max3 thì máy sẽ báo lỗi. Để khắc phục điều này chúng ta thường khai báo các hàm ở đầu chương trình sau đó chúng ta định nghĩa các hàm ở bất kỳ đâu trong chương trình đều được.

Đệ quy

Phân loại đệ quy

  1. Tuyến tính (có 1 lời gọi hàm )
  2. nhị phân( có 2 lời gọi hàm )
  3. Phi tuyến (có vòng lặp )
  4. Hỗ tương(gọi cả hàm khác và chính nó )

VD:

2018-10-05_115342.jpg

Mảng

Khai báo mảng

KiểuDữLiệu TênMảng[số phần tử];

VD: int arr[10];

Mảng 1 chiều arr gồm 10 phần tử thuộc kiểu nguyên. 

Cách truy xuất phần tử trong mảng

Tên Mảng[chỉ số];

Có thể khởi tạo mảng như sau:

int arr[5]= {1,2,3,4,5};

int arr[]= {1,2,3,4,5};

int arr[5]= {1,2,3,4,5,6}; // máy báo lỗi vì quá số lượng phần tử

int arr[5]= {1,2,3};  //thì phần tử arr[3]=arr[4]=0

Mảng 2 chiều

int arr[3][4];// mảng gồm 3 hàng 4 cột

Chú ý: Về nhập mảng cũng tương tự như nhập số nguyên.

String

Khai báo

char TênMảng[số lượng phần tử];

VD: char arr[30];

Nhập

gets(arr);

Xuất

puts(arr);

hoặc printf(“%s”,arr);

Truy xuất phần tử trong mảng

arr[chỉ số];

VD: char arr[6]=”abcde”;

Truy xuất đến phần tử thứ 3 thì: arr[2] ( phần tử này có giá trị bằng ‘c’)

Chú ý: phần tử cuối cùng của chuỗi là NULL hoặc ‘\0’

Một số hàm trong thư viện: #include<ctype.h>

strcpy(đích, nguồn);//sao chép

strcat(s1, s2);//nối s2 vào s1

strlen(s);//lấy độ dài xâu

strcmp(s1,s2);//so sánh 2 xâu

toupper(s);//chuyển thường thành hoa

tolower(s);//chuyển hoa thành thường

islower(s);//thường

isupper(s);//hoa

Struct (Cấu trúc)

Khai báo

struct Tên{
     Khai báo các thành phần;
};

Sau khi có kiểu cấu trúc rồi thì cái kiểu đó nó tương tự như 1 kiểu bình thường (int, float, char,…) và ta chỉ việc khai báo biến nữa là xong. 

Cấu trúc lồng nhau

struct Tên1{
     Khai báo các thành phần; 
};
struct Tên2 {
     Khai báo các thành phần;
     Tên1 <Tên Biến>;
};

Truy cập đến thành phần của struct

<Tên biến cấu trúc>.<Tên thành phần>

Đọc file

1.Khai báo

  • FILE *<biến con trỏ file>
  • Ví dụ: FILE *f; FILE *a;

2.Mở file để đọc ghi

const char *filePath = "C:/Users/ADMIN/Desktop/my_document.txt";
  • Cú pháp: = fopen(“ten_file”, “mode”);

Trong đó

  • bien_file: là con trỏ kiểu FILE đã khai báo
  • ten_file: là tên của file cần đọc/ghi dữ liệu
  • mode: là kiểu mở file (để đọc/ghi)
  • Nếu việc mở file không thành công, bien_file = NULL

Các bạn cần lưu ý rằng file trong máy tính tồn tại ở 2 dạng: file văn bản và file bị mã hóa.

  • File văn bản là những file mà các bạn có thể đọc được khi mở bằng các trình soạn thảo văn bản, thông thường những file này được định dạng Unicode (hoặc những định dạng dùng cho văn bản khác).
  • File bị mã hóa (thường gọi là file nhị phân) không thể đọc được khi mở file bằng các trình soạn thảo văn bản. Sử dụng File bị mã hóa giúp chúng ta bảo mật dữ liệu tốt hơn File văn bản.

3.Các định dạng đọc ghi file

  • r: đọc
  • w: ghi
  • a: thêm
  • t: văn bản
  • b: nhị phân

4.Đóng file trong C

  • Sau khi ghi dữ liệu xong, phải đóng file bằng thủ tục:
    • fclose();
    • Ví dụ: fclose(f); fclose(f1);
  • Hàm kiểm tra file đã kết thúc chưa
    • feof();
    • Nếu file đã kết thúc thì feof() = NULL
  • Nếu kết thúc chương trình mà không đóng file, thì khi mở file sẽ không có dữ liệu
  • Dù mở file để đọc / ghi đều nên đóng file sau khi hoàn tất làm việc với file.

5.Các hàm đọc/ghi file trong C

  • Hàm fgetc();
    • Đọc một kí tự trong file
    • fgetc(stdin) tương đương getchar();
  • Hàm fgets();
    • Đọc một dòng trong file
    • fgets(stdin) tương đương gets();
  • Hàm fputc(‘a’,);
    • Ghi một kí tự vào file
    • fputc(‘a’, stdout) tương đương putc(‘a’);
  • Hàm fputs();
    • fputs(s, stdout) tương đương puts(s);
  • Hàm fprintf(, s);
    • Ghi một xâu s (có định dạng) vào file
  • Hàm fscanf(,s);
    • Đọc dữ liệu từ file

6.Hàm Nhập – Xuất nhị phân trong C

Ghi dữ liệu lên tập tin nhị phân – Hàm fwrite()

Cú pháp: size_t fwrite(const void *ptr, size_t size, size_t n, FILE *f)

ptr: con trỏ chỉ đến vùng nhớ chứa thông tin cần ghi lên tập tin.

n: số phần tử sẽ ghi lên tập tin.

size: kích thước của mỗi phần tử.

f: con trỏ tập tin đã được mở.

Giá trị trả về của hàm này là số phần tử được ghi lên tập tin. Giá trị này bằng n trừ khi xuất hiện lỗi.

Đọc dữ liệu từ tập nhị phân – Hàm fread()

Cú pháp: size_t fread(const void *ptr, size_t size, size_t n, FILE *f)

ptr: con trỏ chỉ đến vùng nhớ sẽ nhận dữ liệu từ tập tin.

n: số phần tử được đọc từ tập tin.

size: kích thước của mỗi phần tử.

f: con trỏ tập tin đã được mở.

  • Một số hàm:

int fseek(FILE *stream, long int offset, int whence)

fseek(f, 0, SEEK_END); //con tro xuong cuoi file (so 0 co nghia la do doi` so voi END)

ftell(f); // lấy độ dài file từ đầu đến vị trí con trỏ

Con trỏ

Khai báo

Kiểu *TênBiến;

VD:

int *p;
int x=10;
p=&x;
*p=20;

Ta dùng toán tử & để lấy địa chỉ của 1 biến và sau đó gán địa chỉ đó cho biến con trỏ.

Tên con trỏ = &biến;

Với con trỏ p bên trên ta có 2 phép tuy xuất là:

  • p: Lấy địa chỉ mà nó lưu giữ (trỏ tới)
  • *p: Lấy giá trị trong vùng nhớ mà nó trỏ tới.

Trong VD trên ta có thể thấy sau phép gán px = &x; thì việc ta viết:

  • p sẽ tương đương với &x
  • *p sẽ tương đương với x. và ta có thể sử dụng *p trong các phép toán, biểu thức.
  • Thao tác phép toán trên *p sẽ làm thay đổi giá trị của biến x;

Cấp phát, thu hồi vùng nhớ cho biến con trỏ

Để cấp phát vùng nhớ cho con trỏ ta dùng các hàm sau trong thư viện stdlib.h.

  • malloc : tên con trỏ = (kiểu con trỏ *) malloc (sizeof(kiểu con trỏ));
  • calloc : tên con trỏ = (kiểu con trỏ *) malloc (n, sizeof(kiểu con trỏ));

Trong đó sizeof(kiểu con trỏ) là kích thước của kiểu; n là số lần của sizeof(kiểu con trỏ) được cấp.

Khi cấp phát cho biến con trỏ 1 số lượng ô nhớ nào đó mà trong quá trình làm việc ta thiếu và cần cấp phát thêm thì ta sử dụng lệnh realloc:

tên con trỏ = (kiểu con trỏ *) realloc (tên con trỏ, số lượng cần cấp phát * sizeof(kiểu con trỏ));

Để thu hổi bộ nhớ đã cấp phát ta dùng hàm free(tên con trỏ);

Tham khảo tại: https://tienich123.wordpress.com/

LEAVE A REPLY

Please enter your comment!
Please enter your name here