Bagaimana cara menentukan ukuran array saya di C?
Artinya, jumlah elemen yang bisa dimiliki array?
Bagaimana cara menentukan ukuran array saya di C?
Artinya, jumlah elemen yang bisa dimiliki array?
Jawaban:
Ringkasan bisnis plan:
int a[17];
size_t n = sizeof(a)/sizeof(a[0]);
Jawaban lengkap:
Untuk menentukan ukuran array Anda dalam byte, Anda dapat menggunakan sizeof
operator:
int a[17];
size_t n = sizeof(a);
Di komputer saya, panjang int adalah 4 byte, jadi n adalah 68.
Untuk menentukan jumlah elemen dalam array, kita dapat membagi ukuran total array dengan ukuran elemen array. Anda bisa melakukan ini dengan tipenya, seperti ini:
int a[17];
size_t n = sizeof(a) / sizeof(int);
dan dapatkan jawaban yang tepat (68/4 = 17), tetapi jika jenis
a
perubahan Anda akan memiliki bug jahat jika Anda lupa untuk mengubah sizeof(int)
juga.
Jadi pembagi yang disukai adalah sizeof(a[0])
atau setara sizeof(*a)
, ukuran elemen pertama array.
int a[17];
size_t n = sizeof(a) / sizeof(a[0]);
Keuntungan lain adalah bahwa Anda sekarang dapat dengan mudah parameterisasi nama array di makro dan dapatkan:
#define NELEMS(x) (sizeof(x) / sizeof((x)[0]))
int a[17];
size_t n = NELEMS(a);
ARRAYSIZE
makro yang didefinisikan di WinNT.h
(yang ditarik oleh header lainnya). Jadi pengguna WinAPI tidak perlu mendefinisikan makro mereka sendiri.
static int a[20];
. Tetapi komentar Anda bermanfaat bagi pembaca yang mungkin tidak menyadari perbedaan antara array dan pointer.
The sizeof
cara adalah cara yang tepat IFF Anda berurusan dengan array tidak diterima sebagai parameter. Array yang dikirim sebagai parameter ke suatu fungsi diperlakukan sebagai pointer, sehingga sizeof
akan mengembalikan ukuran pointer, bukan array.
Dengan demikian, fungsi-fungsi di dalam metode ini tidak berfungsi. Sebagai gantinya, selalu berikan parameter tambahan yang size_t size
menunjukkan jumlah elemen dalam array.
Uji:
#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]) ));
}
Output (dalam OS Linux 64-bit):
sizeof of array: 28
sizeof of parameter: 8
Length of array: 7
Length of parameter: 2
Output (dalam OS windows 32-bit):
sizeof of array: 28
sizeof of parameter: 4
Length of array: 7
Length of parameter: 1
length of parameter:2
jika hanya pointer ke elemen array pertama yang dilewati?
(sizeof array / sizeof *array)
.
Perlu dicatat bahwa sizeof
tidak membantu ketika berhadapan dengan nilai array yang telah membusuk ke pointer: meskipun menunjuk ke awal array, ke kompiler itu sama dengan pointer ke elemen tunggal array itu . Pointer tidak "mengingat" hal lain tentang array yang digunakan untuk menginisialisasi itu.
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 bit. Semua standar mengatakan bahwa nilai integer dari 0 hingga 127 dapat diwakili, dan jangkauannya setidaknya -127 hingga 127 (char ditandatangani) atau 0 hingga 255 (char tidak ditandatangani).
Ukuran "trik" adalah cara terbaik yang saya tahu, dengan satu perubahan kecil tapi (bagi saya, ini menjadi kesal hewan peliharaan) perubahan penting dalam penggunaan tanda kurung.
Seperti yang dijelaskan oleh entri Wikipedia, C's sizeof
bukan fungsi; ini operator . Dengan demikian, tidak memerlukan tanda kurung di sekitar argumennya, kecuali argumennya adalah nama jenis. Ini mudah diingat, karena membuat argumen terlihat seperti ekspresi pemain, yang juga menggunakan tanda kurung.
Jadi: Jika Anda memiliki yang berikut ini:
int myArray[10];
Anda dapat menemukan jumlah elemen dengan kode seperti ini:
size_t n = sizeof myArray / sizeof *myArray;
Bagi saya, itu jauh lebih mudah daripada alternatif dengan tanda kurung. Saya juga menyukai penggunaan tanda bintang di bagian kanan divisi, karena ini lebih ringkas daripada pengindeksan.
Tentu saja, ini semua waktu kompilasi juga, jadi tidak perlu khawatir tentang divisi yang mempengaruhi kinerja program. Jadi gunakan formulir ini di mana pun Anda bisa.
Itu selalu terbaik untuk menggunakan sizeof pada objek yang sebenarnya ketika Anda memilikinya, daripada pada jenis, karena Anda tidak perlu khawatir tentang membuat kesalahan dan menyatakan jenis yang salah.
Misalnya, Anda memiliki fungsi yang menampilkan beberapa data sebagai aliran byte, misalnya melintasi jaringan. Mari kita panggil fungsi tersebut send()
, dan buat sebagai argumen sebagai penunjuk ke objek yang akan dikirim, dan jumlah byte dalam objek. Jadi, prototipe menjadi:
void send(const void *object, size_t size);
Dan kemudian Anda perlu mengirim integer, sehingga Anda membuat kodenya seperti ini:
int foo = 4711;
send(&foo, sizeof (int));
Sekarang, Anda telah memperkenalkan cara halus menembak diri sendiri di kaki, dengan menentukan jenis foo
di dua tempat. Jika satu berubah tetapi yang lain tidak, kode rusak. Jadi, selalu lakukan seperti ini:
send(&foo, sizeof foo);
Sekarang kamu terlindungi. Tentu, Anda menduplikasi nama variabel, tetapi itu memiliki kemungkinan besar untuk memecahkan dengan cara kompiler dapat mendeteksi, jika Anda mengubahnya.
sizeof(int)
memerlukan instruksi yang lebih rendah daripada sizeof(foo)
?
int x = 1+1;
versus int x = (1+1);
. Di sini, tanda kurung murni semata-mata hanya estetika.
sizeof
akan selalu konstan di C ++ dan C89. Dengan array panjang variabel C99, itu dapat dievaluasi saat runtime.
sizeof
mungkin operator tetapi harus diperlakukan sebagai fungsi sesuai dengan Linus Torvalds. Saya setuju. Baca rasionalnya di sini: lkml.org/lkml/2012/7/11/103
int size = (&arr)[1] - arr;
Lihat tautan ini untuk penjelasan
ptrdiff_t
. (Biasanya pada sistem 64-bit, ini akan menjadi tipe yang lebih besar dari int
). Bahkan jika Anda mengubah int
ke ptrdiff_t
dalam kode ini, masih ada bug jika arr
memakan lebih dari setengah ruang alamat.
/3G
opsi Anda memiliki pemisah / kernel 3G / 1G, yang memungkinkan Anda memiliki ukuran array hingga 75% dari ukuran ruang alamat.
foo buf1[80]; foo buf2[sizeof buf1/sizeof buf1[0]]; foo buf3[(&buf1)[1] - buf1];
sebagai variabel global. buf3[]
deklarasi gagal karena (&buf1)[1] - buf1
tidak konstan.
Anda dapat menggunakan operator sizeof tetapi tidak akan berfungsi untuk fungsi karena akan mengambil referensi pointer Anda dapat melakukan hal berikut untuk menemukan panjang array:
len = sizeof(arr)/sizeof(arr[0])
Kode awalnya ditemukan di sini: Program C untuk menemukan jumlah elemen dalam array
Jika Anda mengetahui tipe data array, Anda dapat menggunakan sesuatu seperti:
int arr[] = {23, 12, 423, 43, 21, 43, 65, 76, 22};
int noofele = sizeof(arr)/sizeof(int);
Atau jika Anda tidak tahu tipe data array, Anda dapat menggunakan sesuatu seperti:
noofele = sizeof(arr)/sizeof(arr[0]);
Catatan: Hal ini hanya berfungsi jika array tidak didefinisikan pada saat run (seperti malloc) dan array tidak diteruskan dalam suatu fungsi. Dalam kedua kasus, arr
(nama array) adalah sebuah pointer.
int noofele = sizeof(arr)/sizeof(int);
hanya setengah jalan lebih baik daripada coding int noofele = 9;
. Menggunakan sizeof(arr)
mempertahankan fleksibilitas jika ukuran array berubah. Namun sizeof(int)
kebutuhan pembaruan harus jenis arr[]
perubahan. Lebih baik digunakan sizeof(arr)/sizeof(arr[0])
meski jenisnya sudah terkenal. Tidak jelas mengapa menggunakan int
untuk noofele
vs. size_t
, jenis yang dikembalikan oleh sizeof()
.
Makro ARRAYELEMENTCOUNT(x)
bahwa setiap orang menggunakan evaluasi salah . Ini, secara realistis, hanya masalah sensitif, karena Anda tidak dapat memiliki ekspresi yang menghasilkan tipe 'array'.
/* Compile as: CL /P "macro.c" */
# define ARRAYELEMENTCOUNT(x) (sizeof (x) / sizeof (x[0]))
ARRAYELEMENTCOUNT(p + 1);
Sebenarnya dievaluasi sebagai:
(sizeof (p + 1) / sizeof (p + 1[0]));
Sedangkan
/* Compile as: CL /P "macro.c" */
# define ARRAYELEMENTCOUNT(x) (sizeof (x) / sizeof (x)[0])
ARRAYELEMENTCOUNT(p + 1);
Ini mengevaluasi dengan benar untuk:
(sizeof (p + 1) / sizeof (p + 1)[0]);
Ini benar-benar tidak ada hubungannya dengan ukuran array secara eksplisit. Saya baru saja memperhatikan banyak kesalahan karena tidak benar-benar mengamati cara kerja preprosesor C. Anda selalu membungkus parameter makro, bukan ekspresi yang mungkin terlibat di dalamnya.
Ini benar; contoh saya adalah yang buruk. Tapi sebenarnya itulah yang seharusnya terjadi. Seperti yang saya sebutkan sebelumnya p + 1
akan berakhir sebagai tipe pointer dan membatalkan seluruh makro (seperti jika Anda mencoba menggunakan makro dalam suatu fungsi dengan parameter pointer).
Pada akhirnya, dalam contoh khusus ini , kesalahannya tidak terlalu penting (jadi saya hanya membuang waktu semua orang; huzzah!), Karena Anda tidak memiliki ekspresi dengan jenis 'array'. Tapi sebenarnya poin tentang subtitle evaluasi preprosesor saya pikir adalah yang penting.
(sizeof (x) / sizeof (*x))
?
Untuk array multidimensi , ini sedikit lebih rumit. Seringkali orang mendefinisikan konstanta makro eksplisit, yaitu
#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", " " },
};
Tetapi konstanta ini dapat dievaluasi pada waktu kompilasi juga dengan ukuran :
#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);
Perhatikan bahwa kode ini berfungsi dalam C dan C ++. Untuk array dengan penggunaan lebih dari dua dimensi
sizeof(name[0][0][0])
sizeof(name[0][0][0][0])
dll, tak terhingga.
sizeof(array) / sizeof(array[0])
array
dimiliki, Anda tidak perlu menggunakan sizeof(array) / sizeof(array[0])
apakah array
merupakan array dari keduanya char
, unsigned char
atau signed char
- Kutipan dari C18,6.5.3.4 / 4: "Ketika sizeof diterapkan pada operan yang memiliki tipe char, unsigned char, atau char yang ditandatangani , (atau versi yang memenuhi syarat) hasilnya adalah 1. " Dalam hal ini Anda dapat melakukan sizeof(array)
seperti yang dijelaskan dalam jawaban khusus saya .
Ukuran array di C:
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
belum int
dengan int n = sizeof (a) / sizeof (a[0]);
dan tidaksize_t n = sizeof (a) / sizeof (a[0]);
char a[INT_MAX + 1u];
, int n
seperti yang digunakan di int n = sizeof (a) / sizeof (a[0]);
tidak cukup (ini adalah UB). Penggunaan size_t n = sizeof (a) / sizeof (a[0]);
tidak menimbulkan masalah ini.
Saya akan menyarankan untuk tidak pernah menggunakan sizeof
(bahkan jika itu dapat digunakan) untuk mendapatkan salah satu dari dua ukuran array yang berbeda, baik dalam jumlah elemen atau dalam byte, yang merupakan dua kasus terakhir yang saya tunjukkan di sini. Untuk masing-masing dari dua ukuran, makro yang ditunjukkan di bawah ini dapat digunakan untuk membuatnya lebih aman. Alasannya adalah untuk memperjelas maksud kode untuk pengelola, dan perbedaan sizeof(ptr)
dari sizeof(arr)
pandangan pertama (yang ditulis dengan cara ini tidak jelas), sehingga bug kemudian jelas bagi semua orang yang membaca kode.
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)
(Didefinisikan di bawah) IS diperlukan seperti halnya -Wsizeof-pointer-div
buggy (per April / 2020):
#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__; \
} \
) \
)
Ada bug penting mengenai topik ini: https://lkml.org/lkml/2015/9/3/428
Saya tidak setuju dengan solusi yang disediakan Linus, yaitu tidak pernah menggunakan notasi array untuk parameter fungsi.
Saya suka notasi array sebagai dokumentasi bahwa pointer sedang digunakan sebagai array. Tapi itu berarti bahwa solusi bodoh-bukti perlu diterapkan sehingga tidak mungkin untuk menulis kode kereta.
Dari sebuah array kita memiliki tiga ukuran yang mungkin ingin kita ketahui:
Yang pertama sangat sederhana, dan tidak masalah jika kita berurusan dengan array atau pointer, karena dilakukan dengan cara yang sama.
Contoh penggunaan:
void foo(ptrdiff_t nmemb, int arr[static nmemb])
{
qsort(arr, nmemb, sizeof(arr[0]), cmp);
}
qsort()
membutuhkan nilai ini sebagai argumen ketiga.
Untuk dua ukuran lainnya, yang merupakan topik pertanyaan, kami ingin memastikan bahwa kami berurusan dengan array, dan memecah kompilasi jika tidak, karena jika kita berurusan dengan pointer, kita akan mendapatkan nilai yang salah . Ketika kompilasi rusak, kita akan dapat dengan mudah melihat bahwa kita tidak berurusan dengan sebuah array, tetapi dengan sebuah pointer sebagai gantinya, dan kita hanya perlu menulis kode dengan variabel atau makro yang menyimpan ukuran file. Array di belakang pointer.
Yang ini adalah yang paling umum, dan banyak jawaban telah memberi Anda ARRAY_SIZE makro yang khas:
#define ARRAY_SIZE(arr) (sizeof(arr) / sizeof((arr)[0]))
Mengingat bahwa hasil ARRAY_SIZE biasanya digunakan dengan variabel bertanda jenis ptrdiff_t
, ada baiknya untuk menentukan varian yang ditandatangani dari makro ini:
#define ARRAY_SSIZE(arr) ((ptrdiff_t)ARRAY_SIZE(arr))
Array dengan lebih dari PTRDIFF_MAX
anggota akan memberikan nilai yang tidak valid untuk versi makro yang ditandatangani ini, tetapi dari membaca C17 :: 6.5.6.9, array seperti itu sudah bermain dengan api. Hanya ARRAY_SIZE
dan size_t
harus digunakan dalam kasus-kasus itu.
Versi kompiler terbaru, seperti GCC 8, akan memperingatkan Anda ketika Anda menerapkan makro ini ke sebuah pointer, sehingga aman (ada metode lain untuk membuatnya aman dengan kompiler lama).
Ia bekerja dengan membagi ukuran dalam byte dari seluruh array dengan ukuran setiap elemen.
Contoh penggunaan:
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;
}
Jika fungsi-fungsi ini tidak menggunakan array, tetapi sebagai parameter sebagai gantinya, kode sebelumnya tidak akan dikompilasi, jadi tidak mungkin untuk memiliki bug (mengingat bahwa versi kompiler baru-baru ini digunakan, atau bahwa beberapa trik lain digunakan) , dan kami perlu mengganti panggilan makro dengan nilai:
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
umumnya digunakan sebagai solusi untuk kasus sebelumnya, tetapi kasus ini jarang ditulis dengan aman, mungkin karena itu kurang umum.
Cara umum untuk mendapatkan nilai ini adalah menggunakan sizeof(arr)
. Masalahnya: sama dengan yang sebelumnya; jika Anda memiliki pointer bukan array, program Anda akan menjadi gila.
Solusi untuk masalah ini melibatkan penggunaan makro yang sama seperti sebelumnya, yang kami tahu aman (itu merusak kompilasi jika diterapkan pada pointer):
#define ARRAY_BYTES(arr) (sizeof((arr)[0]) * ARRAY_SIZE(arr))
Cara kerjanya sangat sederhana: itu membatalkan divisi yang ARRAY_SIZE
melakukannya, jadi setelah pembatalan matematika Anda berakhir hanya dengan satu sizeof(arr)
, tetapi dengan keamanan tambahan ARRAY_SIZE
konstruksi.
Contoh penggunaan:
void foo(ptrdiff_t nmemb)
{
int arr[nmemb];
memset(arr, 0, ARRAY_BYTES(arr));
}
memset()
membutuhkan nilai ini sebagai argumen ketiga.
Seperti sebelumnya, jika array diterima sebagai parameter (pointer), array tidak akan dikompilasi, dan kami harus mengganti panggilan makro dengan nilai:
void foo(ptrdiff_t nmemb, int arr[nmemb])
{
memset(arr, 0, sizeof(arr[0]) * nmemb);
}
-Wsizeof-pointer-div
bermasalah :Hari ini saya menemukan bahwa peringatan baru di GCC hanya berfungsi jika makro didefinisikan di header yang bukan header sistem. Jika Anda mendefinisikan makro di header yang diinstal di sistem Anda (biasanya /usr/local/include/
atau /usr/include/
) ( #include <foo.h>
), kompiler TIDAK akan memancarkan peringatan (saya mencoba GCC 9.3.0).
Jadi kita sudah #define ARRAY_SIZE(arr) (sizeof(arr) / sizeof((arr)[0]))
dan ingin membuatnya aman. Kami membutuhkan C11 _Static_assert()
dan beberapa ekstensi GCC: Pernyataan dan Pernyataan dalam Ekspresi , __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]); \
} \
)
Sekarang ARRAY_SIZE()
benar-benar aman, dan karenanya semua turunannya akan aman.
__arraycount()
:Libbsd menyediakan makro __arraycount()
dalam <sys/cdefs.h>
, yang tidak aman karena tidak memiliki sepasang tanda kurung, tetapi kita dapat menambahkan sendiri tanda kurung itu, dan oleh karena itu kita bahkan tidak perlu menulis divisi di header kita (mengapa kita menduplikasi kode yang sudah ada? ). Makro itu didefinisikan dalam header sistem, jadi jika kami menggunakannya kami terpaksa menggunakan makro di atas.
#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))
Beberapa sistem menyediakan nitems()
di <sys/param.h>
sebaliknya, dan beberapa sistem menyediakan baik. Anda harus memeriksa sistem Anda, dan menggunakan yang Anda miliki, dan mungkin menggunakan beberapa persyaratan preprocessor untuk portabilitas dan mendukung keduanya.
Sayangnya, ({})
ekstensi gcc tidak dapat digunakan pada ruang lingkup file. Untuk dapat menggunakan makro pada ruang lingkup file, pernyataan statis harus ada di dalam sizeof(struct {})
. Kemudian, gandakan dengan 0
tidak mempengaruhi hasilnya. Seorang pemain (int)
mungkin baik untuk mensimulasikan fungsi yang kembali (int)0
(dalam hal ini tidak perlu, tetapi kemudian dapat digunakan kembali untuk hal-hal lain).
#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)
) yang tidak ditampilkan di tempat lain: ARRAY_BYTES(arr)
.
sizeof
, tetapi gunakan konstruksi ini sebagai gantinya; jika Anda merasa ingin menulis konstruksi ini setiap kali, Anda kemungkinan akan membuat kesalahan (sangat umum jika Anda menyalin tempel, dan juga sangat umum jika Anda menulisnya setiap kali karena mereka memiliki banyak tanda kurung) ...
sizeof
jelas tidak aman (alasannya ada dalam jawaban), dan tidak menggunakan makro tetapi menggunakan konstruksi yang saya berikan, setiap kali, bahkan lebih tidak aman, jadi satu-satunya cara untuk pergi adalah makro.
"Anda telah memperkenalkan cara halus menembak diri sendiri di kaki"
Array 'asli' tidak menyimpan ukurannya. Oleh karena itu disarankan untuk menyimpan panjang array dalam variabel / const yang terpisah, dan meneruskannya setiap kali Anda melewati array, yaitu:
#define MY_ARRAY_LENGTH 15
int myArray[MY_ARRAY_LENGTH];
Anda HARUS selalu menghindari array asli (kecuali jika Anda tidak bisa, dalam hal ini, pikirkan saja). Jika Anda menulis C ++, gunakan wadah 'vektor' STL . "Dibandingkan dengan array, mereka memberikan kinerja yang hampir sama", dan mereka jauh lebih berguna!
// 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
deklarasi.
#define SIZE_OF_ARRAY(_array) (sizeof(_array) / sizeof(_array[0]))
Jika Anda benar-benar ingin melakukan ini untuk menyebarkan array Anda, saya sarankan menerapkan struktur untuk menyimpan pointer ke tipe yang Anda inginkan dari array dan integer yang mewakili ukuran array. Kemudian Anda bisa mengopernya ke fungsi Anda. Cukup tetapkan nilai variabel array (pointer ke elemen pertama) ke pointer itu. Kemudian Anda bisa pergi Array.arr[i]
untuk mendapatkan elemen ke-i dan menggunakanArray.size
untuk mendapatkan jumlah elemen dalam array.
Saya memasukkan beberapa kode untuk Anda. Ini tidak terlalu berguna tetapi Anda dapat memperluasnya dengan lebih banyak fitur. Jujur saja, jika ini adalah hal yang Anda inginkan, Anda harus berhenti menggunakan C dan menggunakan bahasa lain dengan fitur-fitur ini.
/* 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);
tanpa penanganan overflow.
Cara terbaik adalah Anda menyimpan informasi ini, misalnya, dalam struktur:
typedef struct {
int *array;
int elements;
} list_s;
Terapkan semua fungsi yang diperlukan seperti membuat, menghancurkan, memeriksa kesetaraan, dan semua yang Anda butuhkan. Lebih mudah untuk lulus sebagai parameter.
int elements
vs size_t elements
?
Fungsi sizeof
mengembalikan jumlah byte yang digunakan oleh array Anda di memori. Jika Anda ingin menghitung jumlah elemen dalam array Anda, Anda harus membagi nomor itu dengan sizeof
tipe variabel array. Katakanlah int array[10];
, jika integer tipe variabel di komputer Anda adalah 32 bit (atau 4 byte), untuk mendapatkan ukuran array Anda, Anda harus melakukan hal berikut:
int array[10];
int sizeOfArray = sizeof(array)/sizeof(int);
Anda dapat menggunakan &
operator. Ini kode sumbernya:
#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;
};
Berikut adalah contoh keluarannya
1549216672
1549216712
---- diff----
4
The size of array a is 10
ptrdiff_t
. sizeof()
hasil dalam size_t
. C tidak mendefinisikan mana yang lebih luas atau lebih tinggi / peringkat yang sama. Jadi jenis hasil bagi ((char *)(&a+1)-(char *)a)/(sizeof(a[0]))
tidak tentu size_t
dan dengan demikian pencetakan dengan z
dapat menyebabkan UB. Cukup menggunakan printf("The size of array a is %zu\n", sizeof a/sizeof a[0]);
sudah cukup.
(char *)(&a+1)-(char *)a
bukan konstanta dan dapat dihitung pada saat run-time, bahkan dengan ukuran tetap a[10]
. sizeof(a)/sizeof(a[0])
konstan dilakukan pada waktu kompilasi dalam kasus ini.
Solusi yang lebih elegan
size_t size = sizeof(a) / sizeof(*a);
Di samping jawaban yang sudah disediakan, saya ingin menunjukkan kasus khusus dengan menggunakan
sizeof(a) / sizeof (a[0])
Jika a
array char
, unsigned char
atau signed char
Anda tidak perlu menggunakan sizeof
dua kali sejak sizeof
ekspresi dengan satu operan dari jenis ini selalu menghasilkan 1
.
Kutipan dari C18,6.5.3.4 / 4:
" Ketika
sizeof
diterapkan pada operan yang memiliki jenischar
,unsigned char
atausigned char
, (atau versi yang berkualitas daripadanya) hasilnya adalah1
."
Dengan demikian, sizeof(a) / sizeof (a[0])
akan sama dengan NUMBER OF ARRAY ELEMENTS / 1
jika a
adalah array bertipe char
, unsigned char
atau signed char
. Pembagian melalui 1 adalah mubazir.
Dalam hal ini, Anda cukup menyingkat dan melakukan:
sizeof(a)
Sebagai contoh:
char a[10];
size_t length = sizeof(a);
Jika Anda ingin bukti, berikut ini tautan ke GodBolt .
Meskipun demikian, divisi menjaga keamanan, jika jenisnya berubah secara signifikan (meskipun kasus ini jarang terjadi).
Catatan: Yang ini dapat memberi Anda perilaku tidak terdefinisi seperti yang ditunjukkan oleh MM dalam komentar.
int a[10];
int size = (*(&a+1)-a) ;
*
Operator tidak dapat diterapkan pada pointer masa-the-end
*(&a+1) - a;
berbeda dari di (&a)[1] - a;
atas, jangan keduanya *(&a+1)
dan (&a)[1]
dihitung sebagai 1 melewati akhir?
x[y]
didefinisikan sebagai*(x + (y))