SORU
26 Ocak 2011, ÇARŞAMBA


Nasıl C diziler kullanırım ?

C hemen hemen her yerde kullanıldığı C diziler miras kaldı. C sağlar soyut olan kullanımı kolay ve daha az hata eğilimli (std::vector<T> beri C 98 std::array<T, n> C 11), gerek diziler için değil, ortaya oldukça sıklıkta geliyor C. Ancak, ne zaman okudun eski kod ya da etkileşim ile bir kütüphane ile yazılmış C, o, senin bir firma kavramak üzerinde nasıl bir dizi çalışma.

Bu SSS beş bölüme ayrılır:

  1. arrays on the type level and accessing elements
  2. array creation and initialization
  3. assignment and parameter passing
  4. multidimensional arrays and arrays of pointers
  5. common pitfalls when using arrays

Eğer önemli bir şey bu SSS eksik olduğunu düşünüyorsanız, bir cevap yazıp buraya link ek bir parçası olarak.

Aşağıdaki metin, "" "C dizisi" değil, Sınıf std::array şablon. demek dizi C Bildiricisi sözdizimi ile ilgili temel bilgi kabul edilir. Aşağıda gösterildiği gibi new delete el kullanımı özel durumlar karşısında son derece tehlikeli olduğunu, ancak another FAQ konu olduğunu unutmayın.

(Not: Bu Stack Overflow's C FAQ için bir giriş olarak tasarlanmıştır. Eğer bu formda bir SSS sağlama fikri tenkit etmek istiyorsanız, o zaman the posting on meta that started all this bunu yapmak için bir yer olurdu. Cevaplar soru izlenen C chatroom nereye SSS fikir başladı ilk başta, bu da senin cevabın çok muhtemel alın okuyun o kim buldu bu fikri.)

CEVAP
26 Ocak 2011, ÇARŞAMBA


Tür düzeyinde diziler

Dizi Türü T nerede T[n] olarak gösterilireleman tipive n a pozitifboyutudizideki öğelerin sayısı. Dizi türü öğe türünü ve boyutunu bir ürün türüdür. Yoksa bu maddeler de bir farklılık, farklı bir tür olsun:

#include <type_traits>

static_assert(!std::is_same<int[8], float[8]>::value, "distinct element type");
static_assert(!std::is_same<int[8],   int[9]>::value, "distinct size");

Boyut, farklı boyut dizisi türleri birbirleri ile hiçbir alakası yok uyumsuz tip tip parçası olduğunu unutmayın. sizeof(T[n]) n * sizeof(T) eşdeğerdir.

Dizi için işaretçi çürüme

""T[n] T[m] Her iki tür örtülü olması arasında . bağlantı sadece ^em>dönüştürülmüşT* ve bu dönüşüm sonucu için dizinin ilk öğe için bir işaretçi. Bu, T* gerekli olduğu bir yerde, T[n] ve derleyici sessizce bir işaretçi sağlar: bir sağlayabilir

                   --- --- --- --- --- --- --- --- 
the_actual_array: |   |   |   |   |   |   |   |   |   int[8]
                   --- --- --- --- --- --- --- --- 
                    ^
                    |
                    |
                    |
                    |  pointer_to_the_first_element   int*

Bu dönüşüm olarak bilinen "dizisi için işaretçi çürüme" ve büyük bir karışıklık kaynağı. Dizinin boyutu artık (T*) türü bir parçası olduğundan, bu süreç içinde kaybolur. Artılar: türü düzeyinde bir dizi boyutunu Unutmadan bir işaretçi bir dizinin ilk elemanı işaret sağlarherhangi birboyutu. Con: Verilen bir işaretçi ilk (veya başka bir) elemanı bir dizi, hiçbir şekilde algılamak ne kadar büyük bir dizi ya da tam olarak nerede işaretçi noktalarına göre sınırları dizi. Pointers are extremely stupid.

Diziler işaretçiler değildir

Derleyici sessizce yararlı gördüğü zaman, bir işlem, bir dizi başarısız ama bir işaretçi üzerinde başarılı olmak istiyorum zaman, bir dizinin ilk öğe için bir işaretçi oluşturur. Diziden bu dönüşüm işaretçi için önemsiz, elde edilen işaretçi berideğersadece dizinin adresidir. İşaretçi olduğunu unutmayındeğildizinin kendisi (bellek ya da başka bir yerde) bir parçası olarak depolanır.Bir dizi işaretçisi değil.

static_assert(!std::is_same<int[8], int*>::value, "an array is not a pointer");

Önemli bir bağlam bir dizi yapardeğililk öğe için bir işaretçi içine çürüme & operatörü uygulandığında. Bu durumda, & operatör için bir işaretçi verirtümdizi, ilk öğe için bir işaretçi. Bu durumda olsa dadeğerler(adresleri) aynı, bir dizinin ilk öğe için bir işaretçi var ve tüm dizi için bir işaretçi tamamen farklı türleri vardır:

static_assert(!std::is_same<int*, int(*)[8]>::value, "distinct element type");

Aşağıdaki ASCII sanat bu ayrımı şöyle açıklıyor:

       ----------------------------------- 
      |  --- --- --- --- --- --- --- ---  |
 ---> | |   |   |   |   |   |   |   |   | | int[8]
|     |  --- --- --- --- --- --- --- ---  |
|      ---^------------------------------- 
|         |
|         |
|         |
|         |  pointer_to_the_first_element   int*
|
|  pointer_to_the_entire_array              int(*)[8]

Not nasıl işaretçiyi ilk element sadece puan için bir tek tamsayı (tasvir bir küçük kutu), Oysa bu işaretçi tüm dizi puan bir dizi 8 tamsayı (tasvir büyük bir kutu).

Aynı durum, sınıflar içinde ortaya çıkar ve belki de daha açık. Bir nesne ve ilk veri üyesi için bir işaretçi işaretçi aynıdeğer(aynı Adres), Henüz tamamen farklı türleri vardır.

Eğer C Bildiricisi sözdizimi aşina iseniz, 37* *yazın parantez gerekli:

  • int(*)[8] 8 dizisi için bir işaretçi.
  • int*[8] 8 işaretçiler yazın int* her öğe bir dizi.

Öğelere erişme

C iki cümle çeşitleri bir elemanlarına tek tek erişmek için sağlar. Bunların hiçbiri diğerinden üstün değildir, ve her ikisi de aşina olmanız gerekir.

İşaretçi aritmetiği

Bir işaretçi p bir dizinin ilk elemanı verilen, 42* *ifadesi dizinin i-th öğesi için bir işaretçi verir. Daha sonra bu işaretçi kaldırma, tek tek öğeleri erişebilirsiniz:

std::cout << *(x 3) << ", " << *(x 7) << std::endl;

Eğer x gösterirdizio zaman dizi için işaretçi çürüme olacak, çünkü ekleme bir dizi ve bir tamsayı anlamsız (yok artı operasyonda diziler) ama ekleme işaretçisi bir tamsayı mantıklı:

    --- --- --- --- --- --- --- --- 
x: |   |   |   |   |   |   |   |   |   int[8]
    --- --- --- --- --- --- --- --- 
     ^           ^               ^
     |           |               |
     |           |               |
     |           |               |
x 0  |      x 3  |          x 7  |     int*

(Örtülü olarak oluşturulan bir işaretçi adı yok, sırayla x 0 bunu tanımlamak için yazdım unutmayın.)

Eğer, diğer taraftan, x gösteririşaretçiilk (veya başka bir) elemanı bir dizi, o dizi için işaretçi çürümesine gerek yok, çünkü bu gösterici i olacak eklendi zaten var:

    --- --- --- --- --- --- --- --- 
   |   |   |   |   |   |   |   |   |   int[8]
    --- --- --- --- --- --- --- --- 
     ^           ^               ^
     |           |               |
     |           |               |
    -|-          |               |
x: | | |    x 3  |          x 7  |     int*
    --- 

Not tasvir durumda olan, x bir işaretçideğişken(küçük kutu ** 51) yanında görülebilir, ama olabilir gibi iyi bir işlevi bir işaretçi döndürmek (veya yazın başka bir ifade T*). sonuç

İndeksleme operatörü

53 ** sözdizimi biraz sakar olduğu için, C 54**: alternatif sözdizimi sağlar

std::cout << x[3] << ", " << x[7] << std::endl;

Ayrıca simetriktir olması nedeniyle, aşağıdaki kodu tam olarak aynı işi yapar:

std::cout << 3[x] << ", " << 7[x] << std::endl;

İndeksleme operatörü tanımı şu ilginç denklik yol açar:

&x[i]  ==  &*(x i)  ==  x i

Ancak, &x[0] genellikledeğilx eşdeğer. Eski bir işaretçi, bir dizi ikinci. İçerik tetikler sadece dizi için işaretçi çürümesi x ve &x[0] birbirlerinin yerine kullanılabilir. Örneğin:

T* p = &array[0];  // rewritten as &*(array 0), decay happens due to the addition
T* q = array;      // decay happens due to the assignment

İlk satırında, derleyici basit başarılı bir işaretçi bir işaretçi, bir ödev olarak algılar. İkinci satırda, bir atama algılardizibir işaretçi. Bu anlamsız olduğundan (amaişaretçiatama mantıklı) işaretçi, işaretçi dizi çürüme her zamanki gibi devreye giriyor.

Aralıkları

63* *türü bir dizi n elementler n-1; 67 ** hiçbir unsur yoktur 0 endeksli oldu. Ve yarı açık aralıkları desteklemek için henüz, (başlangıçtaherşey dahilve sonözelC (olmayan) n-th öğesi için bir işaretçi hesaplama sağlar, ama yasadışı olan işaretçi çözümlemesi:),

    --- --- --- --- --- --- --- --- ....
x: |   |   |   |   |   |   |   |   |   .   int[8]
    --- --- --- --- --- --- --- --- ....
     ^                               ^
     |                               |
     |                               |
     |                               |
x 0  |                          x 8  |     int*

Eğer bir dizi sıralamak isterseniz, örneğin, aşağıdaki her ikisi de eşit derecede iyi çalışır:

std::sort(x   0, x   n);
std::sort(&x[0], &x[0]   n);

Not bu yasadışı sağlamak &x[n] olarak ikinci argüman beri bu eşdeğerdir &*(x n) ve alt-ifade *(x n) teknik olarak çağırır undefined behavior C (ama içinde C99).

Ayrıca sadece ilk argüman olarak x sağlar, unutmayın. Bu biraz fazla kısa ve öz tadım ve aynı zamanda yapar şablon değişkeni kesintisi biraz daha derleyici, çünkü bu durumda ilk bağımsız değişken bir dizi ama ikinci argüman bir gösterici. (Yine dizi için işaretçi çürümeye başladı.)

Bunu Paylaş:
  • Google+
  • E-Posta
Etiketler:

YORUMLAR

SPONSOR VİDEO

Rastgele Yazarlar

  • Kat Krazy

    Kat Krazy

    12 Kasım 2010
  • KittiesMama

    KittiesMama

    10 AĞUSTOS 2008
  • The Warp Zone

    The Warp Zon

    24 AĞUSTOS 2007