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 sizeofiş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 *scanfve *printfiş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 xve yfarklı nesnelerdir ave bdeğişiklikler bu nedenle, xve yyansıtılmaz ave b. Biz değerlerini değiştirmek istediğimiz için ave bbiz 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 xve yama ne değerlerini xve y nokta için . Yazmak *x, yazmaktan farklıdır x; değeri xkendi içinde xgü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, streamneyi stream işaret ettiğini değil , dolayısıyla değiştirmenin streamdeğ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.