Diziler ve işlevlerle uğraşırken bir örüntü vardır; ilk başta görmek biraz zor.
Dizilerle uğraşırken, aşağıdakileri hatırlamak yararlıdır: çoğu bağlamda bir dizi ifadesi göründüğünde, ifadenin türü dolaylı olarak "N öğesinin T" dizisinden "pointer to T" ye dönüştürülür ve değeri ayarlanır dizideki ilk öğeye işaret etmek için. Bu kuralın istisnaları, dizi ifadesinin &
veya sizeof
işleçlerinin işleneni olarak göründüğü veya bir bildirimde başlatıcı olarak kullanılan bir dizgi değişmezi olduğu zamandır.
Bu nedenle, dizi ifadesine sahip bir işlevi bağımsız değişken olarak çağırdığınızda, işlev bir dizi değil bir işaretçi alır:
int arr[10];
...
foo(arr);
...
void foo(int *arr) { ... }
Eğer nedeni budur yok kullanmak &
"% s" tekabül argümanlar için operatöre scanf()
:
char str[STRING_LENGTH];
...
scanf("%s", str);
Örtük dönüşüm nedeniyle , dizinin başına işaret scanf()
eden bir char *
değer alır str
. Bu, dizi ifadesi ile bağımsız değişken olarak çağrılan herhangi bir işlev için geçerlidir (hemen hemen tüm str*
işlevler *scanf
ve *printf
işlevler vb.).
Pratikte, büyük olasılıkla &
işleci kullanarak dizi ifadesi içeren bir işlevi aşağıdaki gibi çağırmazsınız :
int arr[N];
...
foo(&arr);
void foo(int (*p)[N]) {...}
Böyle bir kod çok yaygın değildir; işlev bildirimindeki dizinin boyutunu bilmeniz gerekir ve işlev yalnızca belirli boyutlardaki dizilere işaretçilerle çalışır (10 öğeli T dizisine işaretçi, 11 öğeli diziye işaretçiden farklı bir türdür T).
Bir dizi ifadesi, &
operatöre , sonuçta ortaya çıkan ifadenin türü "işaretçi ile T öğesinin T öğesi dizisi" dir veya T (*)[N]
bir işaretçi dizisinden ( T *[N]
) ve bir işaretçi taban türüne ( T *
).
İşlevler ve işaretçilerle uğraşırken hatırlanması gereken kural şudur: bir bağımsız değişkenin değerini değiştirmek ve çağrının koduna yansımasını istiyorsanız, değiştirmek istediğiniz şeye bir işaretçi iletmeniz gerekir. Yine, diziler eserlere biraz İngiliz anahtarı atıyor, ancak önce normal vakalarla ilgileneceğiz.
C'nin tüm işlev bağımsız değişkenlerini değere göre ilettiğini unutmayın; formal parametre, gerçek parametredeki değerin bir kopyasını alır ve formal parametrede yapılan değişiklikler gerçek parametreye yansıtılmaz. Ortak örnek bir takas işlevidir:
void swap(int x, int y) { int tmp = x; x = y; y = tmp; }
...
int a = 1, b = 2;
printf("before swap: a = %d, b = %d\n", a, b);
swap(a, b);
printf("after swap: a = %d, b = %d\n", a, b);
Aşağıdaki çıktıyı alırsınız:
takas etmeden önce: a = 1, b = 2
takastan sonra: a = 1, b = 2
Biçimsel parametreler x
ve y
farklı nesnelerdir a
ve b
değişiklikler bu nedenle, x
ve y
yansıtılmaz a
ve b
. Biz değerlerini değiştirmek istediğimiz için a
ve b
biz geçmelidir işaretçileri takas işlevine onlara:
void swap(int *x, int *y) {int tmp = *x; *x = *y; *y = tmp; }
...
int a = 1, b = 2;
printf("before swap: a = %d, b = %d\n", a, b);
swap(&a, &b);
printf("after swap: a = %d, b = %d\n", a, b);
Şimdi çıktınız
takas etmeden önce: a = 1, b = 2
takastan sonra: a = 2, b = 1
Takas işlevinde, biz değerlerini değişmez, unutmayın x
ve y
ama ne değerlerini x
ve y
nokta için . Yazmak *x
, yazmaktan farklıdır x
; değeri x
kendi içinde x
güncellemiyoruz, bu konumdan bir konum alıyor ve bu konumdaki değeri güncelliyoruz.
Bir işaretçi değerini değiştirmek istiyorsak, bu eşit derecede doğrudur; yazarsak
int myFopen(FILE *stream) {stream = fopen("myfile.dat", "r"); }
...
FILE *in;
myFopen(in);
giriş parametresinin değerini değiştiriyoruz, stream
neyi stream
işaret ettiğini değil , dolayısıyla değiştirmenin stream
değeri üzerinde hiçbir etkisi yoktur in
; bunun çalışması için işaretçiye bir işaretçi geçirmeliyiz:
int myFopen(FILE **stream) {*stream = fopen("myFile.dat", "r"); }
...
FILE *in;
myFopen(&in);
Yine, diziler eserlere biraz İngiliz anahtarı atar. Bir işleve dizi ifadesi ilettiğinizde, işlevin aldığı şey bir işaretçidir. Dizi aboneliğinin nasıl tanımlandığından dolayı, bir işaretçi üzerinde bir alt simge operatörünü bir dizide kullanabileceğiniz gibi kullanabilirsiniz:
int arr[N];
init(arr, N);
...
void init(int *arr, int N) {size_t i; for (i = 0; i < N; i++) arr[i] = i*i;}
Dizi nesnelerinin atanamayabileceğini unutmayın; yani, böyle bir şey yapamazsın
int a[10], b[10];
...
a = b;
dizilere işaretçilerle uğraşırken dikkatli olmak istersiniz; gibi bir şey
void (int (*foo)[N])
{
...
*foo = ...;
}
çalışmaz.