C dizimin boyutunu nasıl belirlerim?
Yani, dizinin tutabileceği eleman sayısı?
C dizimin boyutunu nasıl belirlerim?
Yani, dizinin tutabileceği eleman sayısı?
Yanıtlar:
Yönetici Özeti:
int a[17];
size_t n = sizeof(a)/sizeof(a[0]);
Tam cevap:
Dizinizin bayt cinsinden boyutunu belirlemek için sizeof
işleci kullanabilirsiniz :
int a[17];
size_t n = sizeof(a);
Bilgisayarımda ints 4 bayt uzunluğunda, n ise 68.
Dizideki öğelerin sayısını belirlemek için dizinin toplam boyutunu dizi öğesinin boyutuna bölebiliriz. Bunu tür ile yapabilirsiniz, şöyle:
int a[17];
size_t n = sizeof(a) / sizeof(int);
ve uygun cevabı alın (68/4 = 17), fakat eğer
a
değiştirilirse değiştirmeyi unutursanız kötü bir hataya sahip olursunuz sizeof(int)
.
Dolayısıyla, tercih edilen bölen sizeof(a[0])
ya da eşdeğerdir sizeof(*a)
, dizinin ilk elemanının boyutudur.
int a[17];
size_t n = sizeof(a) / sizeof(a[0]);
Başka bir avantaj, bir makrodaki dizi adını kolayca parametreleştirebilmeniz ve şunları elde edebilmenizdir:
#define NELEMS(x) (sizeof(x) / sizeof((x)[0]))
int a[17];
size_t n = NELEMS(a);
ARRAYSIZE
tanımlanmış makro vardır WinNT.h
(diğer başlıklar tarafından içeri alınır). Bu yüzden WinAPI kullanıcılarının kendi makrolarını tanımlamaları gerekmez.
static int a[20];
. Ancak yorumunuz, bir dizi ile işaretçi arasındaki farkı fark etmeyebilecek okuyucular için kullanışlıdır.
sizeof
Yolu doğru yoldur IFF Eğer parametre olarak alınmayan diziler ile ilgileniyor. Bir işleve parametre olarak gönderilen bir dizi işaretçi olarak kabul edilir, bu nedenle sizeof
dizinin yerine işaretçinin boyutunu döndürür.
Böylece, fonksiyonların içinde bu yöntem çalışmaz. Bunun yerine, her zaman size_t size
dizideki öğe sayısını belirten ek bir parametre iletin.
Ölçek:
#include <stdio.h>
#include <stdlib.h>
void printSizeOf(int intArray[]);
void printLength(int intArray[]);
int main(int argc, char* argv[])
{
int array[] = { 0, 1, 2, 3, 4, 5, 6 };
printf("sizeof of array: %d\n", (int) sizeof(array));
printSizeOf(array);
printf("Length of array: %d\n", (int)( sizeof(array) / sizeof(array[0]) ));
printLength(array);
}
void printSizeOf(int intArray[])
{
printf("sizeof of parameter: %d\n", (int) sizeof(intArray));
}
void printLength(int intArray[])
{
printf("Length of parameter: %d\n", (int)( sizeof(intArray) / sizeof(intArray[0]) ));
}
Çıktı (64 bit Linux işletim sisteminde):
sizeof of array: 28
sizeof of parameter: 8
Length of array: 7
Length of parameter: 2
Çıkış (32 bit Windows işletim sisteminde):
sizeof of array: 28
sizeof of parameter: 4
Length of array: 7
Length of parameter: 1
length of parameter:2
sadece 1. dizi elemanına bir işaretçi geçilirse?
(sizeof array / sizeof *array)
.
sizeof
Bir işaretçiye çürümüş bir dizi değeri ile uğraşırken yardımcı olmadığını belirtmek gerekir : bir dizinin başlangıcını göstermesine rağmen, derleyiciye o dizinin tek bir öğesinin işaretçisi ile aynıdır . Bir işaretçi, diziyi başlatmak için kullanılan dizi hakkında başka bir şey "hatırlamaz".
int a[10];
int* p = a;
assert(sizeof(a) / sizeof(a[0]) == 10);
assert(sizeof(p) == sizeof(int*));
assert(sizeof(*p) == sizeof(int));
char
32 bitlik C'ye sahip olduğunu hatırlıyorum . Tüm standart, 0 ile 127 arasındaki tamsayı değerlerinin temsil edilebileceği ve aralığının en az -127 ile 127 (karakter imzalı) veya 0 ile 255 (karakter imzasız) olabileceğidir.
"Hile" boyutu, bildiğim en iyi yol, bir küçük ama (bana göre, bu büyük bir evcil hayvan huşu) parantez kullanımında önemli bir değişiklik.
Wikipedia girişinin de belirttiği gibi, C'ler sizeof
bir işlev değildir; bir operatör . Bu nedenle, argüman bir tür adı olmadığı sürece argümanının etrafında parantez gerektirmez. Bunu hatırlamak kolaydır, çünkü argümanı parantez kullanan döküm ifadesine benzetir.
Yani: Aşağıdakilere sahipseniz:
int myArray[10];
Kodu olan öğelerin sayısını şu şekilde bulabilirsiniz:
size_t n = sizeof myArray / sizeof *myArray;
Bu, bana göre, parantez alternatifinden çok daha kolay okur. Ayrıca, yıldızın dizinin sağ tarafında kullanılmasını tercih ediyorum, çünkü endekslemeden daha özlü.
Tabii ki, bu da derleme zamanıdır, bu nedenle programın performansını etkileyen bölüm hakkında endişelenmenize gerek yoktur. Yani bu formu mümkün olan her yerde kullanın.
Bir tür yerine, bir nesneye sahip olduğunuzda gerçek bir nesnede sizeof kullanmak her zaman en iyisidir, çünkü o zaman bir hata yapma ve yanlış türü belirleme konusunda endişelenmenize gerek yoktur.
Örneğin, örneğin bir ağ üzerinden bazı verileri bayt akışı olarak çıkaran bir işleviniz olduğunu varsayalım. İşlevi çağıralım ve send()
argüman olarak gönderilecek nesneye bir işaretçi ve nesnedeki bayt sayısını almasını sağlayalım. Böylece, prototip şöyle olur:
void send(const void *object, size_t size);
Ve sonra bir tamsayı göndermeniz gerekir, böylece bunu şöyle kodlayabilirsiniz:
int foo = 4711;
send(&foo, sizeof (int));
Şimdi, foo
iki yerde türünü belirterek kendinizi ayağa vurmanın ince bir yolunu tanıttınız . Biri değişir ancak diğeri değişmezse kod kırılır. Böylece, her zaman böyle yapın:
send(&foo, sizeof foo);
Artık korunuyorsunuz. Elbette, değişkenin adını çoğaltırsınız, ancak değiştirirseniz derleyicinin algılayabileceği şekilde kırılma olasılığı yüksektir.
sizeof(int)
az talimat gerektirir sizeof(foo)
mi?
int x = 1+1;
Karşı düşün int x = (1+1);
. Burada parantezler kesinlikle sadece estetiktir.
sizeof
C ++ ve C89'da her zaman sabit olacak. C99'un değişken uzunluklu dizileri ile çalışma zamanında değerlendirilebilir.
sizeof
operatör olabilir ancak Linus Torvalds'a göre bir işlev olarak ele alınmalıdır. Katılıyorum. Rasyonelini buradan okuyun: lkml.org/lkml/2012/7/11/103
int size = (&arr)[1] - arr;
Açıklama için bu bağlantıya göz atın
ptrdiff_t
. (Genellikle 64 bit sistemde, bu daha büyük bir tür olacaktır int
). Değiştirmek bile int
için ptrdiff_t
bu kodda, yine bir hata var arr
adres alanının yarısından fazlasını kaplar.
/3G
isteğe bağlı olarak, adres alanı boyutunun% 75'ine kadar diziler boyutuna sahip olmanızı sağlayan 3G / 1G kullanıcı / çekirdek bölünmesine sahiptir.
foo buf1[80]; foo buf2[sizeof buf1/sizeof buf1[0]]; foo buf3[(&buf1)[1] - buf1];
Global değişkenler olarak düşünün . sabit olmadığı için buf3[]
bildirim başarısız (&buf1)[1] - buf1
olur.
Sizeof operatörünü kullanabilirsiniz, ancak bir dizinin uzunluğunu bulmak için aşağıdakileri yapabileceğiniz işaretçinin referansını alacağı için işlevler için çalışmaz:
len = sizeof(arr)/sizeof(arr[0])
Kod burada bulundu: C programı bir dizideki öğe sayısını bulmak için
Dizinin veri türünü biliyorsanız, şöyle bir şey kullanabilirsiniz:
int arr[] = {23, 12, 423, 43, 21, 43, 65, 76, 22};
int noofele = sizeof(arr)/sizeof(int);
Veya dizinin veri türünü bilmiyorsanız, aşağıdaki gibi bir şey kullanabilirsiniz:
noofele = sizeof(arr)/sizeof(arr[0]);
Not: Bu şey yalnızca dizi çalışma zamanında tanımlanmadıysa (malloc gibi) ve dizi bir işlevde geçmediğinde çalışır. Her iki durumda da arr
(dizi adı) bir göstericidir.
int noofele = sizeof(arr)/sizeof(int);
kodlamadan sadece yarı yol daha iyidir int noofele = 9;
. Kullanılması sizeof(arr)
esneklik dizi boyutunda değişiklik gerektiğini korur. Yine sizeof(int)
de, arr[]
değişiklik türünün güncellenmesi gerekir . sizeof(arr)/sizeof(arr[0])
Türü iyi bilinse bile kullanmak daha iyidir. Neden vs. int
için kullanıldığını , döndüren türü açık değil . noofele
size_t
sizeof()
ARRAYELEMENTCOUNT(x)
Herkesin kullandığı makro yanlış değerlendirilir . Bu, gerçekçi bir şekilde, sadece hassas bir konudur, çünkü 'dizi' türüyle sonuçlanan ifadelere sahip olamazsınız.
/* Compile as: CL /P "macro.c" */
# define ARRAYELEMENTCOUNT(x) (sizeof (x) / sizeof (x[0]))
ARRAYELEMENTCOUNT(p + 1);
Aslında şu şekilde değerlendirir:
(sizeof (p + 1) / sizeof (p + 1[0]));
Buna karşılık
/* Compile as: CL /P "macro.c" */
# define ARRAYELEMENTCOUNT(x) (sizeof (x) / sizeof (x)[0])
ARRAYELEMENTCOUNT(p + 1);
Aşağıdakileri doğru bir şekilde değerlendirir:
(sizeof (p + 1) / sizeof (p + 1)[0]);
Bunun gerçekten dizilerin boyutu ile açıkça ilgisi yoktur. C ön işlemcisinin nasıl çalıştığını gerçekten gözlemlememekten kaynaklanan birçok hata fark ettim. İçinde olabilecek bir ifade değil, her zaman makro parametresini kaydırırsınız.
Doğru; benim örneğim kötü bir örnekti. Ama aslında tam olarak ne olması gerekiyor. Daha önce de belirttiğim p + 1
gibi, bir işaretçi türü olarak sona erecek ve tüm makroyu geçersiz kılacaktır (makroyu bir pointer parametresine sahip bir işlevde kullanmaya çalıştığınız gibi).
Günün sonunda, bu özel durumda, hata gerçekten önemli değil (bu yüzden sadece herkesin zamanını boşa harcıyorum; huzzah!), Çünkü bir tür 'dizi' ile ifadeleriniz yok. Ama gerçekten de önişlemci değerlendirmesiyle ilgili önemli nokta bence önemli.
(sizeof (x) / sizeof (*x))
?
Çok boyutlu diziler için biraz daha karmaşıktır. Genellikle insanlar açık makro sabitleri tanımlar, yani
#define g_rgDialogRows 2
#define g_rgDialogCols 7
static char const* g_rgDialog[g_rgDialogRows][g_rgDialogCols] =
{
{ " ", " ", " ", " 494", " 210", " Generic Sample Dialog", " " },
{ " 1", " 330", " 174", " 88", " ", " OK", " " },
};
Ancak bu sabitler, derleme zamanında sizeof ile de değerlendirilebilir :
#define rows_of_array(name) \
(sizeof(name ) / sizeof(name[0][0]) / columns_of_array(name))
#define columns_of_array(name) \
(sizeof(name[0]) / sizeof(name[0][0]))
static char* g_rgDialog[][7] = { /* ... */ };
assert( rows_of_array(g_rgDialog) == 2);
assert(columns_of_array(g_rgDialog) == 7);
Bu kod C ve C ++ ile çalıştığını unutmayın. İkiden fazla boyutu olan diziler için
sizeof(name[0][0][0])
sizeof(name[0][0][0][0])
vb. reklam sonsuz.
sizeof(array) / sizeof(array[0])
array
, kullanılan gerekmez etti sizeof(array) / sizeof(array[0])
halinde array
bir dizi ya olduğu char
, unsigned char
ya da signed char
- C18,6.5.3.4 / 4'ten Alıntı: "sizeof tipi kömürü, unsigned char veya imzalı karakter vardır bir işlenen uygulandığında , (veya nitelikli bir sürümü) sonucu 1 olur. " Bu durumda, sizeof(array)
özel cevabımda açıklandığı gibi yapabilirsiniz .
C dizisinin boyutu:
int a[10];
size_t size_of_array = sizeof(a); // Size of array a
int n = sizeof (a) / sizeof (a[0]); // Number of elements in array a
size_t size_of_element = sizeof(a[0]); // Size of each element in array a
// Size of each element = size of type
size_t size_of_element
henüz int
sahip int n = sizeof (a) / sizeof (a[0]);
değilsize_t n = sizeof (a) / sizeof (a[0]);
char a[INT_MAX + 1u];
, int n
kullanılan int n = sizeof (a) / sizeof (a[0]);
(UB olan) yetersizdir. Kullanmak size_t n = sizeof (a) / sizeof (a[0]);
bu sorunla karşılaşmaz.
Ben sizeof
burada göstermek son iki durumda olan elemanların sayısı veya bayt, herhangi bir dizi iki farklı boyutlardan birini almak için (kullanılabilir olsa bile) asla kullanmanızı tavsiye ederim. İki boyutun her biri için, aşağıda gösterilen makrolar daha güvenli hale getirmek için kullanılabilir. Bunun nedeni açıktır maintainers'ı kod niyeti ve fark yaratmak için sizeof(ptr)
gelen sizeof(arr)
ilk bakışta böcek sonra herkes kodunu okumak için ortada böylece, (bu şekilde yazılı açık değildir).
TL; DR:
#define ARRAY_SIZE(arr) (sizeof(arr) / sizeof((arr)[0]) + must_be_array(arr))
#define ARRAY_SSIZE(arr) ((ptrdiff_t)ARRAY_SIZE(arr))
#define ARRAY_BYTES(arr) (sizeof((arr)[0]) * ARRAY_SIZE(arr))
must_be_array(arr)
(aşağıda tanımlanmıştır) -Wsizeof-pointer-div
Buggy olduğu gibi IS gerekli (nisan / 2020 itibariyle):
#define is_same_type(a, b) __builtin_types_compatible_p(typeof(a), typeof(b))
#define is_array(a) (!is_same_type((a), &(a)[0]))
#define Static_assert_array(a) _Static_assert(is_array(a), "Not a `[]` !")
#define must_be_array(a) ( \
0 * (int)sizeof( \
struct { \
Static_assert_array(a); \
char ISO_C_forbids_a_struct_with_no_members__; \
} \
) \
)
Bu konuyla ilgili önemli hatalar oluştu: https://lkml.org/lkml/2015/9/3/428
Ben işlev parametreleri için dizi gösterimi asla kullanmak Linus sağladığı çözüm ile katılmıyorum.
Dizi gösterimi bir işaretçi dizi olarak kullanılan belgeler olarak seviyorum. Ancak bu, hata kodunun yazılmasının imkansız olması için kusursuz bir çözümün uygulanması gerektiği anlamına gelir.
Bir diziden bilmek isteyebileceğimiz üç boyut var:
Birincisi çok basit ve bir dizi veya işaretçi ile uğraşmamızın önemi yok, çünkü aynı şekilde yapıldı.
Kullanım örneği:
void foo(ptrdiff_t nmemb, int arr[static nmemb])
{
qsort(arr, nmemb, sizeof(arr[0]), cmp);
}
qsort()
üçüncü argüman olarak bu değere ihtiyaç duyar.
Sorunun konusu olan diğer iki boyut için, bir dizi ile uğraştığımızdan emin olmak ve eğer değilse derlemeyi kırmak istiyoruz, çünkü bir işaretçi ile uğraşırsak yanlış değerler alırız . Derleme bozulduğunda, bir dizi ile uğraşmadığımızı, ancak bunun yerine bir işaretçi ile kolayca görebileceğiz ve kodu, değişkenin boyutunu depolayan bir değişken veya makro ile yazmamız gerekecek. İşaretçinin arkasındaki dizi.
Bu en yaygın olanıdır ve birçok yanıt size tipik ARRAY_SIZE makrosunu sağlamıştır:
#define ARRAY_SIZE(arr) (sizeof(arr) / sizeof((arr)[0]))
ARRAY_SIZE sonucunun yaygın olarak işaretli tür değişkenleriyle kullanıldığı göz önüne alındığında ptrdiff_t
, bu makronun işaretli bir varyantını tanımlamak iyidir:
#define ARRAY_SSIZE(arr) ((ptrdiff_t)ARRAY_SIZE(arr))
Birden fazla PTRDIFF_MAX
üyesi olan diziler , makronun bu imzalı sürümü için geçersiz değerler verecek, ancak C17 :: 6.5.6.9 okunurken, bunun gibi diziler zaten ateşle oynuyor. Sadece ARRAY_SIZE
ve size_t
bu durumlarda kullanılmalıdır.
GCC 8 gibi derleyicilerin son sürümleri, bu makroyu bir işaretçiye uyguladığınızda sizi uyaracaktır, bu nedenle güvenlidir (eski derleyicilerle güvenli hale getirmek için başka yöntemler vardır).
Tüm dizinin baytlarındaki boyutu her öğenin boyutuna bölerek çalışır.
Kullanım örnekleri:
void foo(ptrdiff_t nmemb)
{
char buf[nmemb];
fgets(buf, ARRAY_SIZE(buf), stdin);
}
void bar(ptrdiff_t nmemb)
{
int arr[nmemb];
for (ptrdiff_t i = 0; i < ARRAY_SSIZE(arr); i++)
arr[i] = i;
}
Bu işlevler dizileri kullanmadıysa, ancak bunları parametre olarak aldıysa, eski kod derlenmezdi, bu nedenle bir hataya sahip olmak imkansız olurdu (son derleyici sürümünün kullanılması veya başka bir hile kullanılması durumunda) ve makro çağrısını aşağıdaki değerle değiştirmemiz gerekir:
void foo(ptrdiff_t nmemb, char buf[nmemb])
{
fgets(buf, nmemb, stdin);
}
void bar(ptrdiff_t nmemb, int arr[nmemb])
{
for (ptrdiff_t i = 0; i < nmemb; i++)
arr[i] = i;
}
ARRAY_SIZE
bir önceki durum için bir çözüm olarak yaygın olarak kullanılır, ancak bu durum nadiren güvenli bir şekilde yazılır, belki daha az yaygın olduğu için.
Bu değeri elde etmenin yaygın yolu kullanmaktır sizeof(arr)
. Sorun: bir öncekiyle aynı; dizi yerine bir işaretçiniz varsa, programınız çıldırır.
Sorunun çözümü, güvenli olduğunu bildiğimiz daha önceki ile aynı makronun kullanılmasını içerir (bir işaretçiye uygulanırsa derlemeyi keser):
#define ARRAY_BYTES(arr) (sizeof((arr)[0]) * ARRAY_SIZE(arr))
Nasıl çalıştığı çok basit: Yaptığı bölümü geri alır ARRAY_SIZE
, bu nedenle matematiksel iptallerden sonra sadece bir tane ile sonuçlanırsınız sizeof(arr)
, ancak yapının ek güvenliği ile ARRAY_SIZE
.
Kullanım örneği:
void foo(ptrdiff_t nmemb)
{
int arr[nmemb];
memset(arr, 0, ARRAY_BYTES(arr));
}
memset()
üçüncü argüman olarak bu değere ihtiyaç duyar.
Daha önce olduğu gibi, dizi parametre (işaretçi) olarak alınırsa, derlenmez ve makro çağrısını aşağıdaki değerle değiştirmeniz gerekir:
void foo(ptrdiff_t nmemb, int arr[nmemb])
{
memset(arr, 0, sizeof(arr[0]) * nmemb);
}
-Wsizeof-pointer-div
buggy :Bugün, GCC'deki yeni uyarının yalnızca makro bir sistem başlığı olmayan bir başlıkta tanımlanmışsa işe yaradığını öğrendim. Makroyu sisteminizde yüklü olan bir başlıkta (genellikle /usr/local/include/
veya /usr/include/
) ( #include <foo.h>
) tanımlarsanız, derleyici bir uyarı yaymaz (GCC 9.3.0'ı denedim).
Bu yüzden #define ARRAY_SIZE(arr) (sizeof(arr) / sizeof((arr)[0]))
güvenli hale getirmek istiyoruz ve istiyoruz. C11 _Static_assert()
ve bazı GCC uzantılarına ihtiyacımız olacak : İfadelerdeki İfadeler ve Beyanlar , __builtin_types_compatible_p :
#define is_same_type(a, b) __builtin_types_compatible_p(typeof(a), typeof(b))
#define is_array(a) (!is_same_type((a), &(a)[0]))
#define Static_assert_array(a) _Static_assert(is_array(a), "Not a `[]` !")
#define ARRAY_SIZE(arr) ( \
{ \
Static_assert_array(arr); \
sizeof(arr) / sizeof((arr)[0]); \
} \
)
Şimdi ARRAY_SIZE()
tamamen güvenlidir ve bu nedenle tüm türevleri güvende olacaktır.
__arraycount()
:Libbsd makro sağlar __arraycount()
içinde <sys/cdefs.h>
parantez çifti bulunmadığı için güvensiz, ama biz bu parantezleri kendimizi ekleyebilir ve bu nedenle biz bile (neden biz zaten var o kodu çoğaltmak istiyorum bizim başlığındaki bölünme yazmaya gerek yok mu? ). Bu makro bir sistem başlığında tanımlanır, bu yüzden onu kullanırsak yukarıdaki makroları kullanmak zorunda kalırız.
#include <sys/cdefs.h>
#define is_same_type(a, b) __builtin_types_compatible_p(typeof(a), typeof(b))
#define is_array(a) (!is_same_type((a), &(a)[0]))
#define Static_assert_array(a) _Static_assert(is_array(a), "Not a `[]` !")
#define ARRAY_SIZE(arr) ( \
{ \
Static_assert_array(arr); \
__arraycount((arr)); \
} \
)
#define ARRAY_SSIZE(arr) ((ptrdiff_t)ARRAY_SIZE(arr))
#define ARRAY_BYTES(arr) (sizeof((arr)[0]) * ARRAY_SIZE(arr))
Bazı sistemler sağlamak nitems()
içinde <sys/param.h>
yerine ve bazı sistemler hem sağlarlar. Sisteminizi kontrol etmeli ve sahip olduğunuz sistemi kullanmalısınız ve her ikisi de taşınabilirlik ve destek için bazı önişlemci koşullarını kullanmalısınız.
Maalesef, ({})
gcc uzantısı dosya kapsamında kullanılamaz. Makroyu dosya kapsamında kullanabilmek için, statik bildirimin içinde olması gerekir sizeof(struct {})
. Ardından, 0
sonucu etkilememek için ile çarpın . Oyuncular (int)
, geri dönen bir işlevi simüle etmek için iyi olabilir (int)0
(bu durumda gerekli değildir, ancak daha sonra başka şeyler için tekrar kullanılabilir).
#include <sys/cdefs.h>
#define is_same_type(a, b) __builtin_types_compatible_p(typeof(a), typeof(b))
#define is_array(a) (!is_same_type((a), &(a)[0]))
#define Static_assert_array(a) _Static_assert(is_array(a), "Not a `[]` !")
#define must_be_array(a) ( \
0 * (int)sizeof( \
struct { \
Static_assert_array(a); \
char ISO_C_forbids_a_struct_with_no_members__; \
} \
) \
)
#define ARRAY_SIZE(arr) (__arraycount((arr)) + must_be_array(arr))
#define ARRAY_SSIZE(arr) ((ptrdiff_t)ARRAY_SIZE(arr))
#define ARRAY_BYTES(arr) (sizeof((arr)[0]) * ARRAY_SIZE(arr))
sizeof(arr)
başka gösterilmemiştir): ARRAY_BYTES(arr)
.
sizeof
, bunun yerine bu yapıları kullanmak; Bu yapıları her seferinde yazmak istiyorsanız, muhtemelen bir hata yapacaksınız (yapıştırmayı kopyalarsanız çok yaygındır ve her seferinde çok fazla parantezleri olduğu için yazarsanız çok yaygındır) ...
sizeof
bir açıkça güvensiz (nedenler cevapta) ve makroları kullanmıyorum ama sağladığım yapıları kullanmak her seferinde daha güvensiz, bu yüzden gitmenin tek yolu makrolardır.
"kendini ayağından vurmanın ince bir yolunu tanıttın"
C 'doğal' diziler boyutlarını saklamaz. Bu nedenle, dizinin uzunluğunu ayrı bir değişken / const içine kaydetmeniz ve diziyi her geçirdiğinizde geçirmeniz önerilir:
#define MY_ARRAY_LENGTH 15
int myArray[MY_ARRAY_LENGTH];
Her zaman yerel dizilerden kaçınmalısınız (bu durumda ayağınıza dikkat edemezseniz). C ++ yazıyorsanız, STL'nin 'vektör' kapsayıcısını kullanın. "Dizilerle karşılaştırıldığında neredeyse aynı performansı sağlıyorlar" ve çok daha kullanışlılar!
// vector is a template, the <int> means it is a vector of ints
vector<int> numbers;
// push_back() puts a new value at the end (or back) of the vector
for (int i = 0; i < 10; i++)
numbers.push_back(i);
// Determine the size of the array
cout << numbers.size();
enum
bildirim kullanmak olduğunu okudum .
#define SIZE_OF_ARRAY(_array) (sizeof(_array) / sizeof(_array[0]))
Gerçekten dizi etrafında geçmek için yapmak istiyorsanız ben bir dizi istediğiniz tipe bir işaretçi ve dizinin boyutunu temsil eden bir tamsayı depolamak için bir yapı kullanmanızı öneririz. Sonra bunu işlevlerinize aktarabilirsiniz. Bu değişkene dizi değişken değerini (ilk öğeye işaretçi) atamanız yeterlidir. Daha sonra Array.arr[i]
i-th öğesini almaya gidebilir Array.size
ve dizideki öğe sayısını almak için kullanabilirsiniz .
Size bazı kodlar ekledim. Çok kullanışlı değil, ancak daha fazla özellik ile genişletebilirsiniz. Dürüst olmak gerekirse, bunlar istediğiniz şeylerse, C'yi kullanmayı bırakmalı ve yerleşik bu özelliklerle başka bir dil kullanmalısınız.
/* Absolutely no one should use this...
By the time you're done implementing it you'll wish you just passed around
an array and size to your functions */
/* This is a static implementation. You can get a dynamic implementation and
cut out the array in main by using the stdlib memory allocation methods,
but it will work much slower since it will store your array on the heap */
#include <stdio.h>
#include <string.h>
/*
#include "MyTypeArray.h"
*/
/* MyTypeArray.h
#ifndef MYTYPE_ARRAY
#define MYTYPE_ARRAY
*/
typedef struct MyType
{
int age;
char name[20];
} MyType;
typedef struct MyTypeArray
{
int size;
MyType *arr;
} MyTypeArray;
MyType new_MyType(int age, char *name);
MyTypeArray newMyTypeArray(int size, MyType *first);
/*
#endif
End MyTypeArray.h */
/* MyTypeArray.c */
MyType new_MyType(int age, char *name)
{
MyType d;
d.age = age;
strcpy(d.name, name);
return d;
}
MyTypeArray new_MyTypeArray(int size, MyType *first)
{
MyTypeArray d;
d.size = size;
d.arr = first;
return d;
}
/* End MyTypeArray.c */
void print_MyType_names(MyTypeArray d)
{
int i;
for (i = 0; i < d.size; i++)
{
printf("Name: %s, Age: %d\n", d.arr[i].name, d.arr[i].age);
}
}
int main()
{
/* First create an array on the stack to store our elements in.
Note we could create an empty array with a size instead and
set the elements later. */
MyType arr[] = {new_MyType(10, "Sam"), new_MyType(3, "Baxter")};
/* Now create a "MyTypeArray" which will use the array we just
created internally. Really it will just store the value of the pointer
"arr". Here we are manually setting the size. You can use the sizeof
trick here instead if you're sure it will work with your compiler. */
MyTypeArray array = new_MyTypeArray(2, arr);
/* MyTypeArray array = new_MyTypeArray(sizeof(arr)/sizeof(arr[0]), arr); */
print_MyType_names(array);
return 0;
}
strcpy(d.name, name);
.
En iyi yol, bu bilgileri örneğin bir yapıya kaydetmektir:
typedef struct {
int *array;
int elements;
} list_s;
Oluşturma, yok etme, eşitliği kontrol etme ve ihtiyacınız olan diğer her şey gibi gerekli tüm işlevleri uygulayın. Parametre olarak geçmek daha kolaydır.
int elements
vs. size_t elements
?
İşlev sizeof
diziniz tarafından bellekte kullanılan bayt sayısını döndürür. Dizinizdeki öğe sayısını hesaplamak istiyorsanız, bu sayıyı dizinin sizeof
değişken türüne bölmelisiniz . Diyelim ki int array[10];
, bilgisayarınızdaki değişken türü tamsayı 32 bit (veya 4 bayt) ise, dizinizin boyutunu elde etmek için aşağıdakileri yapmanız gerekir:
int array[10];
int sizeOfArray = sizeof(array)/sizeof(int);
&
Operatörü kullanabilirsiniz . Kaynak kod:
#include<stdio.h>
#include<stdlib.h>
int main(){
int a[10];
int *p;
printf("%p\n", (void *)a);
printf("%p\n", (void *)(&a+1));
printf("---- diff----\n");
printf("%zu\n", sizeof(a[0]));
printf("The size of array a is %zu\n", ((char *)(&a+1)-(char *)a)/(sizeof(a[0])));
return 0;
};
İşte örnek çıktı
1549216672
1549216712
---- diff----
4
The size of array a is 10
ptrdiff_t
. sizeof()
ile sonuçlanır size_t
. C hangisinin daha geniş veya daha yüksek / aynı rütbe olduğunu tanımlamaz. Dolayısıyla bölümün türü ((char *)(&a+1)-(char *)a)/(sizeof(a[0]))
kesinlikle değildir size_t
ve bu nedenle ile baskı z
yapmak UB'ye yol açabilir. Basitçe kullanmak printf("The size of array a is %zu\n", sizeof a/sizeof a[0]);
yeterlidir.
(char *)(&a+1)-(char *)a
sabit değildir ve sabit boyutta bile çalışma zamanında hesaplanabilir a[10]
. sizeof(a)/sizeof(a[0])
bu durumda derleme zamanında sabit yapılır.
Daha zarif bir çözüm
size_t size = sizeof(a) / sizeof(*a);
Halihazırda verilen cevapların yanı sıra,
sizeof(a) / sizeof (a[0])
Eğer a
birinin bir dizidir char
, unsigned char
ya signed char
kullanmak gerekmez sizeof
bir yana iki kez sizeof
her zaman için neden yok bu tür bir işlenen ifade 1
.
C18,6.5.3.4 / 4'ten alıntı:
" Ne zaman
sizeof
bir tür olan işlenen uygulanırchar
,unsigned char
ya dasigned char
, (ya da bunun bir yetkili versiyonu) sonucudur1
."
Bu durumda, sizeof(a) / sizeof (a[0])
eşdeğer olacaktır NUMBER OF ARRAY ELEMENTS / 1
eğer a
tipte bir dizi char
, unsigned char
veya signed char
. 1'e bölünme gereksizdir.
Bu durumda, basitçe kısaltabilir ve yapabilirsiniz:
sizeof(a)
Örneğin:
char a[10];
size_t length = sizeof(a);
Bir kanıt istiyorsanız, işte GodBolt'a bir bağlantı .
Bununla birlikte, tür önemli ölçüde değişirse (bu durumlar nadir olmasına rağmen) bölüm güvenliği korur.
Not: Bu, yorumda MM'nin işaret ettiği gibi tanımlanmamış davranışlar verebilir.
int a[10];
int size = (*(&a+1)-a) ;
*
Operatör bir son-uç işaretçi uygulanmayabilir
*(&a+1) - a;
farklıdır (&a)[1] - a;
hem yukarıda yok *(&a+1)
ve (&a)[1]
sonunda geçmiş 1 sayılır?
x[y]
*(x + (y))