
PH L C 4Ụ Ụ
HÀM V I Đ I S B T Đ NH TRONG CỚ Ố Ố Ấ Ị
Trong các giáo trình C th ng ch h ng d n cách xây d ngườ ỉ ướ ẫ ự
hàm v i các đ i c đ nh. M i đ i c n có m t tham s (cùng ki uớ ố ố ị ỗ ố ầ ộ ố ể
v i nó) trong l i g i hàm. Tuy nhiên m t vài hàm chu n c a C l iớ ờ ọ ộ ẩ ủ ạ
không nh v y, mà linh ho t h n, ch ng khi dùng hàm printf hayư ậ ạ ơ ẳ
scanf thì s tham s mà ta cung c p cho hàm là không c đ nh cố ố ấ ố ị ả
v s l ng l n ki u cách. Ví d trong câu l nh:ề ố ượ ẫ ể ụ ệ
printf(“\n T ng = %d “ , 3+4+5) ;ổ
có 2 tham s , nh ng trong câu l nh:ố ư ệ
printf(“\n Hà N i“ ) ;ộ
ch có m t tham s .ỉ ộ ố
Nh v y c n phân bi t các khái ni m sau: ư ậ ầ ệ ệ
- Đ i s c đ nh đ c khai báo trong dòng đ u c a hàm, nó cóố ố ố ị ượ ầ ủ
tên và ki uể
- Tham s ng v i đ i s c đ nh g i là tham s c đ nhố ứ ớ ố ố ố ị ọ ố ố ị
- Đ i b t đ nh đ c khai báo b i ba d u ch m: b t đ nh c vố ấ ị ượ ở ấ ấ ấ ị ả ề
s l ng và ki uố ượ ể
- Tham s b t đ nh ( ng v i đ i b t đ nh) là m t danh sách giáố ấ ị ứ ớ ố ấ ị ộ
tr v i s l ng và ki u tuỳ ý (không xác đ nh) ị ớ ố ượ ể ị
Trong ph l c này s trình b y cách xây d ng các hàm v i đ iụ ụ ẽ ầ ự ớ ố
s b t đ nh. Công c ch y u đ c dùng là con tr và danh sách. ố ấ ị ụ ủ ế ượ ỏ
1. Bi n con tr ế ỏ
Bi n con tr (hay con tr ) dùng đ ch a đ a ch c a bi n,ế ỏ ỏ ể ứ ị ỉ ủ ế
m ng, hàm, ... Có nhi u ki u đ a ch , vì v y cũng có nhi u ki uả ề ể ị ỉ ậ ề ể
con tr . Bi n con tr đ c khai báo theo m u:ỏ ế ỏ ượ ẫ
Ki u *Tên_bi n_con_tr ;ể ế ỏ
Ví d :ụ
float px ; // px là con tr th c ỏ ự
Các phép toán quan tr ng trên con tr g m:ọ ỏ ồ
+ Gán đ a ch m t vùng nh cho con tr (dùng toán t gán, phépị ỉ ộ ớ ỏ ử
l y đ a ch , các hàm c p phát b nh )ấ ị ỉ ấ ộ ớ
+ Truy nh p vào vùng nh thông qua con tr , dùng phép toán:ậ ớ ỏ
*Tên_con_trỏ
(Đ ý đây có 2 vùng nh : vùng nh c a bi n con tr và vùngể ở ớ ớ ủ ế ỏ
nh mà đ a ch đ u c a nó ch a trong bi n con tr )ớ ị ỉ ầ ủ ứ ế ỏ
+ C ng đ a ch đ con tr ch a đ a ch c a ph n t ti p theo,ộ ị ỉ ể ỏ ứ ị ỉ ủ ầ ử ế
dùng phép toán:
++ Tên_con_tr ho c Tên_con_tr ++ỏ ặ ỏ
Chú ý r ng các phép toán trên ch có th th c hi n đ i v i conằ ỉ ể ự ệ ố ớ
tr có ki u. ỏ ể
2. Danh sách không cùng ki uể
Dùng con tr có ki u ch qu n lý đ c m t danh sách giá trỏ ể ỉ ả ượ ộ ị
cùng ki u, ví d d y s th c, d y s nguyên, d y các c u trúc,....ể ụ ẫ ố ự ẫ ố ẫ ấ
Khi c n qu n lý m t danh sách các giá tr không cùng ki u taầ ả ộ ị ể
ph i dùng con tr không ki u (void) khai báo nh sau:ả ỏ ể ư
void * Tên_con_tr ;ỏ
Con tr void có th ch a các đ a ch có ki u b t kỳ, và dùng đỏ ể ứ ị ỉ ể ấ ể
tr đ n vùng nh ch a danh sách c n qu n lý. M t chú ý quanỏ ế ớ ứ ầ ả ộ
tr ng là m i khi g i vào hay l y ra m t giá tr t vùng nh , thì tuỳọ ỗ ử ấ ộ ị ừ ớ
theo ki u giá tr mà ta ph i dùng phép chuy n ki u thích h p đ iể ị ả ể ể ợ ố
v i con tr . Ví d sau minh ho cách l p m t danh sách g m m tớ ỏ ụ ạ ậ ộ ồ ộ
s nguyên, m t s th c và m t chu i ký t . Chúng ta c n m t bố ộ ố ự ộ ỗ ự ầ ộ ộ
nh đ ch a s nguyên, s th c và đ a ch chu i và dùng các conớ ể ứ ố ố ự ị ỉ ỗ
tr void đ qu n lý vùng nh này.ỏ ể ả ớ
void *list , *p ; // Con tr list tr t i đ u danh sách ỏ ỏ ớ ầ
// p dùng đ duy t qua các ph n t c a danh sách ể ệ ầ ử ủ
list=malloc(sizeof(int) + sizeof(float)+ sizeof(char*) );
p=list;
561 562

*((int*)p) = 12; // Đ a s nguyên 12 vào danh sách ư ố
((int*)p)++ ; // Chuy n sang ph n t ti p theo ể ầ ử ế
*((float*)p) = 3.14; // Đ a s th c 3.14 vào danh sách ư ố ự
((float*)p)++ ; // Chuy n sang ph n t ti p theo ể ầ ử ế
*((char**)p) = “HA NOI”; // Đ a đ a ch chu i “HA NOI” ư ị ỉ ỗ
// vào danh sách
// Nh n các ph n t trong danh sách ậ ầ ử
p=list; // V đ u danh sách ề ầ
int a = *((int*)p); // Nh n ph n t th nh t ậ ầ ử ứ ấ
((int*)p)++ ; // Chuy n sang ph n t ti p theo ể ầ ử ế
float x= *((float*)p); // Nh n ph n t th hai ậ ầ ử ứ
((float*)p)++ ; // Chuy n sang ph n t ti p theo ể ầ ử ế
char *str = *((char**)p) ; // Nh n ph n t th ba ậ ầ ử ứ
3. Hàm v i đ i s b t đ nh ớ ố ố ấ ị
+ Đ i b t đ nh bao gi cũng đ t sau cùng và đ c khai báoố ấ ị ờ ặ ượ
b ng d u ba ch m. Ví d ví d hàmằ ấ ấ ụ ụ
void f(int n, char *s, ...) ;
có 2 đ i c đ nh là n, s và đ i b t đ nh.ố ố ị ố ấ ị
+ Đ nh n đ c các tham s b t đ nh trong l i g i hàm ta c nể ậ ượ ố ấ ị ờ ọ ầ
l u ý các đi m sau:ư ể
- Các tham s b t đ nh ch a trong m t danh sách. Đ nh nố ấ ị ứ ộ ể ậ
đ c đ a ch đ u danh sách ta dùng m t con tr void và phép gánượ ị ỉ ầ ộ ỏ
sau:
void *list ;
list = ... ;
- Dùng m t tham s c đ nh ki u chu i đ quy đ nh s l ngộ ố ố ị ể ỗ ể ị ố ượ
và ki u c a m i tham s trong danh sách, ví d : ể ủ ỗ ố ụ
“3i” hi u là : tham s b t đ nh g m 3 giá tr intể ố ấ ị ồ ị
“3f” hi u là : tham s b t đ nh g m 3 giá tr floatể ố ấ ị ồ ị
“fiss” hi u là có 4 tham s b t đ nh có ki u l n l t là float,ể ố ấ ị ể ầ ượ
int, char*, char*
M t khi đã bi t đ c đ a ch đ u danh sách, bi t đ c s l ngộ ế ượ ị ỉ ầ ế ượ ố ượ
và ki u c a m i tham s , thì d dàng nh n đ c giá tr các thamể ủ ỗ ố ễ ậ ượ ị
s đ s d ng trong thân hàm.ố ể ử ụ
Ví dụ sau đây minh ho cách xây d ng các hàm v i tham s b tạ ự ớ ố ấ
đ nh. Hàm dùng đ in các giá tr ki u int, float và char. Hàm có m tị ể ị ể ộ
tham s c đ nh đ cho bi t có bao nhiêu giá tr và ki u các giá trố ố ị ể ế ị ể ị
c n in. ầKi u quy đ nh nh sau: i là int, f là float, s là char*. Thamể ị ư
s có 2 cách vi t: l p (g m m t h ng s nguyên và m t ch cáiố ế ặ ồ ộ ằ ố ộ ữ
đ nh ki u) và li t kê (m t d y các ch cái đ nh ki u). Ví d :ị ể ệ ộ ẫ ữ ị ể ụ
“4s” có nghĩa in 4 chu iỗ
“siif” có nghĩa in m t chu i, 2 giá tr nguyên và m t giá trộ ỗ ị ộ ị
th c:ự
#include <stdio.h>
#include <ctype.h>
#include <string.h>
#include <conio.h>
#include <stdlib.h>
#include <stdarg.h>
void InDanhSachGiaTri(char *st,...)
{
void *list ;
int gt_int ;
float gt_float;
char *gt_str;
int n,i ;
char kieu;
int lap;
list = ... ; // list tro toi vung nho chua danh sach dia chi cac
563 564

// tham so
lap = isdigit(st[0]) ;
if (lap)
n=st[0] - '0' ;
else
n=strlen(st);
printf("\n n= %d lap = %d",n,lap); getch();
for(i=0;i<n;++i)
{
if(lap)
kieu=st[1];
else
kieu = st[i];
printf("\nKieu= %c",kieu); getch();
switch(kieu)
{
case 'i' :
gt_int = *((int*)list);
if(!lap)
((int*)list)++ ;
printf("\nGia tri %d = %d",i,gt_int);
break;
case 'f' :
gt_float = (float) (*((double*)list));
if(!lap)
((double*)list)++ ;
printf("\nGia tri %d = %0.2f",i,gt_float);
break;
case 's' :
gt_str = *((char**)list) ;
if(!lap)
((char**)list)++ ;
printf("\nGia tri %d = %s",i,gt_str);
}
}
}
void main()
{
float x=3.14;
int a=123;
char *tp="HAI PHONG";
InDanhSachGiaTri("4i",a);
InDanhSachGiaTri("4s","HA NOI");
InDanhSachGiaTri("ifsssffii", a, x, tp, tp,"QUY NHON",
x, 6.28, a, 246);
InDanhSachGiaTri("4f",6.28);
getch();
}
4. Hàm không đ i và hàm v i đ i b t đ nhố ớ ố ấ ị
Nhi u ng i nghĩ hàm khai báo nh sauề ườ ư
void f();
là hàm không đ i trong C. Trong C++ thì hi u nh th là đúng, cònố ể ư ế
trong C thì đó là hàm có đ i b t đ nh (hàm không đ i trong C khaiố ấ ị ố
báo nh sau: f(void) ). Do không có đ i c đ nh nào cho bi t v sư ố ố ị ế ề ố
l ng và ki u c a các tham s b t đ nh, nên gi i pháp đây làượ ể ủ ố ấ ị ả ở
565 566

dùng các bi n toàn b . Rõ ràng gi i pháp này không không thu nế ộ ả ậ
ti n cho ng i dùng vì ph i khai báo đúng tên bi n toàn b và ph iệ ườ ả ế ộ ả
kh i gán giá tr cho nó tr c khi g i hàm. Ví d trình b y m t hàmở ị ướ ọ ụ ầ ộ
ch có đ i b t đ nh dùng đ tính max và min c a các giá tr th c.ỉ ố ấ ị ể ủ ị ự
Các tham s b t đ nh đ c đ a vào theo trình t sau: Đ a ch ch aố ấ ị ượ ư ự ị ỉ ứ
max, đ a ch ch a min, các giá tr nguyên c n tính max, min.ị ỉ ứ ị ầ
Ch ng trình dùng bi n toàn b N đ cho bi t s giá tr nguyênươ ế ộ ể ế ố ị
c n tính max, min.ầ
int N;
void maxmin()
{
void *lt = ... ;
float *max, *min , tg;
int i;
max = *((float**)lt)++;
min = *((float**)lt)++;
*max = *min = (float) *((double*)lt)++;
for(i=1;i<N;++i)
{
tg= (float) *((double*)lt)++;
if(tg > *max) *max = tg;
if(tg < *min) *min = tg;
}
}
567