Bagaimana cara menentukan ukuran array saya di C?
Artinya, jumlah elemen array dapat tahan?
Ringkasan eksekutif:
int a[17];
size_t n = sizeof(a)/sizeof(a[0]);
Jawaban penuh:
Untuk menentukan ukuran dalam byte array, anda dapat menggunakan ukuran
operator:
int a[17];
size_t n = sizeof(a);
Di komputer saya, ints 4 byte panjang, jadi n adalah 68.
Untuk menentukan jumlah elemen dalam array, kita dapat membagi total ukuran dari array dengan ukuran elemen array. Anda bisa melakukan ini dengan jenis, seperti ini:
int a[17];
size_t n = sizeof(a) / sizeof(int);
dan mendapatkan jawaban yang tepat (68 / 4 = 17), tetapi jika jenis
a
berubah, anda akan memiliki bug jahat jika anda lupa untuk mengubah
the sizeof(int)
juga.
Jadi pilihan pembagi adalah sizeof(a[0])
, ukuran
zeroeth elemen dari array.
int a[17];
size_t n = sizeof(a) / sizeof(a[0]);
Keuntungan lain adalah bahwa anda sekarang dapat dengan mudah mengukur array nama di makro dan mendapatkan:
#define NELEMS(x) (sizeof(x) / sizeof((x)[0]))
int a[17];
size_t n = NELEMS(a);
The sizeof
cara adalah cara yang tepat iff anda berurusan dengan array tidak diterima sebagai parameter. Array yang dikirim sebagai parameter ke fungsi diperlakukan sebagai pointer, jadi sizeof
akan mengembalikan pointer's ukuran, bukan array's.
Dengan demikian, dalam fungsi metode ini tidak bekerja. Sebaliknya, selalu melewati parameter tambahan size_t size
yang menunjukkan jumlah elemen dalam array.
Tes:
#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]) ));
}
Keluaran (64-bit OS Linux):
sizeof of array: 28
sizeof of parameter: 8
Length of array: 7
Length of parameter: 2
Keluaran (32-bit OS windows):
sizeof of array: 28
sizeof of parameter: 4
Length of array: 7
Length of parameter: 1
Perlu dicatat bahwa ukuran
doesn't membantu ketika berhadapan dengan sebuah array nilai yang telah membusuk untuk pointer: meskipun poin ke awal array, untuk compiler itu adalah sama sebagai pointer untuk satu elemen dari array. Pointer tidak "ingat" apa pun tentang array yang digunakan untuk menginisialisasi.
int a[10];
int* p = a;
assert(sizeof(a) / sizeof(a[0]) == 10);
assert(sizeof(p) == sizeof(int*));
assert(sizeof(*p) == sizeof(int));
Ukuran "trik" adalah cara terbaik yang saya tahu, dengan satu kecil tapi (bagi saya, ini menjadi besar hewan peliharaan mengesalkan) perubahan penting dalam penggunaan tanda kurung.
Sebagai entri Wikipedia membuat jelas, C's sizeof
bukan fungsi; it's operator. Dengan demikian, tidak memerlukan tanda kurung di sekitar argumen kecuali argumen adalah nama jenis. Ini adalah mudah untuk diingat, karena itu membuat argumen terlihat seperti pemain ekspresi, yang juga menggunakan tanda kurung.
Jadi: Jika anda memiliki yang berikut:
int myArray[10];
Anda dapat menemukan jumlah elemen dengan kode seperti ini:
size_t n = sizeof myArray / sizeof *myArray;
Yang, bagi saya, membaca jauh lebih mudah daripada alternatif dengan tanda kurung. Saya juga mendukung penggunaan tanda bintang di bagian kanan divisi, karena itu's lebih ringkas dari pengindeksan.
Tentu saja, ini semua waktu kompilasi juga, jadi ada's tidak perlu khawatir tentang pembagian mempengaruhi kinerja program. Jadi gunakan formulir ini di mana pun anda bisa.
Itu selalu terbaik untuk menggunakan sizeof pada yang sebenarnya objek ketika anda memiliki satu, bukan pada jenis, karena anda don't perlu khawatir tentang membuat kesalahan dan menyatakan yang salah ketik.
Sebagai contoh, katakanlah anda memiliki sebuah fungsi yang output beberapa data sebagai aliran byte, misalnya di jaringan. Let's memanggil fungsi kirim()
, dan membuatnya mengambil argumen pointer ke objek untuk mengirim, dan jumlah byte dalam objek. Jadi, prototipe menjadi:
void send(const void *object, size_t size);
Dan kemudian anda perlu untuk mengirim sebuah integer, sehingga anda kode seperti ini:
int foo = 4711;
send(&foo, sizeof (int));
Sekarang, anda've memperkenalkan halus cara menembak diri di kaki, dengan menentukan jenis foo
di dua tempat. Jika salah satu perubahan tapi doesn't, kode istirahat. Dengan demikian, selalu melakukan hal seperti ini:
send(&foo, sizeof foo);
Sekarang anda're dilindungi. Yakin, anda menduplikasi nama variabel, tetapi yang memiliki probabilitas tinggi dari melanggar di jalan compiler dapat mendeteksi, jika anda mengubah itu.
Anda dapat menggunakan operator sizeof tapi itu tidak akan bekerja untuk fungsi karena itu akan mengambil referensi dari pointer anda bisa melakukan hal berikut untuk menemukan panjang dari array:
len = sizeof(arr)/sizeof(arr[0])
Kode awalnya ditemukan di sini: C program untuk menemukan jumlah elemen dalam array
Jika anda mengetahui tipe data dari 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 don't mengetahui tipe data dari array, anda dapat menggunakan sesuatu seperti:
noofele = sizeof(arr)/sizeof(arr[0]);
Catatan: hal Ini hanya bekerja jika array tidak didefinisikan pada jangka waktu (seperti malloc) dan array tidak lulus dalam sebuah fungsi. Dalam kedua kasus, arr
(array name) adalah pointer.
Makro ARRAYELEMENTCOUNT(x)
bahwa setiap orang membuat penggunaan mengevaluasi salah. Ini, secara realistis, ini hanya masalah sensitif, karena anda dapat't memiliki ekspresi yang mengakibatkan 'array' jenis.
/* Compile as: CL /P "macro.c" */
# define ARRAYELEMENTCOUNT(x) (sizeof (x) / sizeof (x[0]))
ARRAYELEMENTCOUNT(p + 1);
Actually mengevaluasi 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);
Itu benar mengevaluasi ke:
(sizeof (p + 1) / sizeof (p + 1)[0]);
Ini benar-benar doesn't memiliki banyak yang harus dilakukan dengan ukuran array secara eksplisit. I've hanya melihat banyak kesalahan dari tidak benar-benar mengamati bagaimana C preprocessor bekerja. Anda selalu membungkus parameter makro, bukan sebuah ekspresi dalam mungkin terlibat dalam.
Ini adalah benar; contoh saya adalah yang buruk. Tapi yang's benar-benar persis apa yang harus terjadi. Seperti yang saya sebutkan sebelumnya p + 1
akan berakhir sebagai penunjuk jenis dan membatalkan seluruh makro (seperti jika anda mencoba untuk menggunakan macro dalam suatu fungsi dengan parameter pointer).
Pada akhir hari, ini particular contoh, kesalahan doesn't benar-benar peduli (jadi saya'm hanya membuang-buang setiap orang's waktu; sabas!), karena anda don't memiliki ekspresi dengan tipe 'array'. Tapi benar-benar butir soal preprocessor evaluasi subtles saya pikir adalah salah satu yang penting.
Untuk array multidimensi ini adalah sedikit lebih rumit. Seringkali orang mendefinisikan eksplisit makro konstanta, 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", " " },
};
Tapi konstanta ini dapat dievaluasi pada saat compile-time juga dengan sizeof:
#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 bekerja di C dan C++. Untuk array dengan lebih dari dua dimensi menggunakan
sizeof(name[0][0][0])
sizeof(name[0][0][0][0])
dll., ad infinitum.
Ukuran dari sebuah 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
"anda've memperkenalkan halus cara menembak diri di kaki"
C 'pribumi' array tidak menyimpan ukuran mereka. Oleh karena itu dianjurkan untuk menyimpan panjang array dalam variabel terpisah/const, dan lulus setiap kali anda melewati array, yaitu:
#define MY_ARRAY_LENGTH 15
int myArray[MY_ARRAY_LENGTH];
Anda HARUS selalu menghindari asli array (kecuali jika anda dapat't, yang dalam hal ini, pikiran anda berjalan kaki). Jika anda menulis C++, menggunakan STL's 'vektor' wadah. "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();
Jika anda benar-benar ingin melakukan ini untuk lulus sekitar anda menginap saya sarankan menerapkan struktur untuk menyimpan pointer ke jenis yang anda inginkan array dari integer yang mewakili ukuran dari array. Kemudian anda bisa melewati sekitar untuk fungsi anda. Hanya menetapkan variabel array nilai (pointer ke elemen pertama) untuk pointer itu. Kemudian anda dapat pergi Array.arr[i]
untuk mendapatkan saya-th elemen dan menggunakan Array.ukuran
untuk mendapatkan jumlah elemen dalam array.
Saya termasuk beberapa kode untuk anda. It's tidak sangat berguna, tetapi anda bisa memperpanjang dengan lebih banyak fitur. Jujur meskipun, jika ini adalah hal-hal yang anda inginkan anda harus berhenti menggunakan C dan menggunakan bahasa lain dengan fitur ini dibangun di.
/* 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;
}
Cara terbaik adalah anda menyimpan informasi ini, misalnya, dalam struktur:
typedef struct {
int *array;
int elements;
} list_s;
Melaksanakan semua fungsi yang diperlukan seperti menciptakan, menghancurkan, memeriksa kesetaraan, dan segala sesuatu yang anda butuhkan. Hal ini lebih mudah untuk lulus sebagai parameter.
Fungsi sizeof
mengembalikan jumlah byte yang digunakan oleh array dalam memori. Jika anda ingin menghitung jumlah elemen dalam array, anda harus membagi jumlah itu dengan ukuran
jenis variabel array. Let's mengatakan array int[10];
, jika variabel tipe integer dalam komputer anda 32 bit (4 byte), dalam rangka untuk mendapatkan ukuran dari array, anda harus melakukan berikut ini:
int array[10];
int sizeOfArray = sizeof(array)/sizeof(int);
Saya akan menyarankan untuk tidak pernah menggunakan ukuran
(bahkan jika dapat digunakan) untuk mendapatkan salah satu dari dua ukuran yang berbeda dari sebuah array, baik dalam jumlah elemen atau byte, yang terakhir dua kasus yang saya tampilkan di sini. Untuk masing-masing dari dua ukuran, makro ditunjukkan di bawah ini dapat digunakan untuk membuatnya lebih aman. Alasannya adalah untuk membuat jelas maksud dari kode untuk pengelola, dan perbedaan sizeof(ptr)
dari sizeof(arr)
pada pandangan pertama (yang ditulis dengan cara ini isn't jelas), sehingga bug maka jelas bagi setiap orang yang membaca kode.
Ada bug penting mengenai topik ini: https://lkml.org/lkml/2015/9/3/428 Saya tidak setuju dengan solusi yang Linus, yang adalah untuk tidak pernah menggunakan sejumlah notasi untuk parameter fungsi. Saya suka notasi array sebagai dokumentasi yang pointer yang digunakan sebagai array. Tapi itu berarti bahwa orang bodoh-bukti solusi yang perlu diterapkan sehingga tidak mungkin untuk menulis kode kereta. Dari array kita memiliki tiga ukuran yang kita mungkin ingin tahu:
Yang pertama adalah sangat sederhana, dan itu doesn't peduli jika kita berhadapan dengan sebuah array atau pointer, karena itu's dilakukan dengan cara yang sama.
Contoh penggunaan:
batal foo(ptrdiff_t nmemb, int arr[statis nmemb]) { qsort(arr, nmemb, sizeof(arr[0]), cmp); }
qsort()
kebutuhan nilai ini sebagai argumen ketiga.
Untuk lainnya dua ukuran, yang merupakan topik dari pertanyaan, kami ingin memastikan bahwa kami're berurusan dengan array, dan istirahat kompilasi jika tidak, karena jika kita're berhadapan dengan pointer, kita akan mendapatkan nilai-nilai yang salah. Ketika kompilasi rusak, kita akan dapat dengan mudah melihat bahwa kita tidak't berurusan dengan array, tapi dengan pointer sebaliknya, dan kita hanya akan harus menulis kode dengan variabel atau makro yang menyimpan ukuran array di belakang pointer.
Yang satu ini adalah yang paling umum, dan banyak jawaban telah menyediakan anda dengan khas makro ARRAY_SIZE: ``
Mengingat bahwa hasil dari ARRAY_SIZE umumnya digunakan dengan menandatangani variabel jenis `ptrdiff_t`, itu baik untuk menentukan ditandatangani varian makro ini:
Array dengan lebih dari `PTRDIFF_MAX` anggota akan memberikan nilai yang tidak valid untuk ini ditandatangani versi makro, tapi dari membaca C17::6.5.6.9, array seperti yang sudah bermain dengan api. Hanya `ARRAY_SIZE` dan `size_t` harus digunakan dalam kasus tersebut. Versi terbaru dari compiler seperti GCC 8, akan memperingatkan anda ketika anda menerapkan makro ini untuk pointer, sehingga aman (ada metode lain untuk membuatnya aman dengan yang lebih tua compiler). Ia bekerja dengan membagi ukuran dalam byte dari seluruh array dengan ukuran masing-masing elemen. Contoh penggunaan:
batal foo(ptrdiff_t nmemb)
{
char buf[nmemb];
fgets(buf, ARRAY_SIZE(buf), stdin);
}
batal bar(ptrdiff_t nmemb)
{
int arr[nmemb];
untuk (ptrdiff_t i = 0; i < ARRAY_SSIZE(arr); i++)
arr[i] = i;
}
Jika fungsi ini tidak't menggunakan array, tapi punya mereka sebagai parameter sebaliknya, mantan code tidak akan mengkompilasi, jadi itu akan menjadi mustahil untuk memiliki bug (mengingat bahwa baru-baru ini versi compiler yang digunakan, atau yang beberapa trik lain yang digunakan), dan kita perlu untuk mengganti makro panggilan dengan nilai:
batal foo(ptrdiff_t nmemb, char buf[nmemb])
{
fgets(buf, nmemb, stdin);
}
batal bar(ptrdiff_t nmemb, int arr[nmemb])
{
untuk (ptrdiff_t i = 0; i < nmemb; i++)
arr[i] = i;
}
``
ARRAY_SIZE
ini biasanya digunakan sebagai solusi untuk kasus sebelumnya, tetapi hal ini jarang ditulis dengan aman, mungkin karena itu's kurang umum.
Cara yang umum untuk mendapatkan nilai ini adalah dengan menggunakan sizeof(arr)
. Masalah: sama dengan sebelumnya; jika anda memiliki pointer bukan array, program anda akan pergi kacang.
Solusi untuk masalah ini melibatkan menggunakan makro yang sama seperti sebelumnya, yang kita tahu untuk menjadi aman (istirahat kompilasi jika hal ini diterapkan untuk pointer):
``
Cara kerjanya sangat sederhana: itu membatalkan pembagian yang `ARRAY_SIZE` tidak, jadi setelah matematika pembatalan anda berakhir hanya dengan satu `sizeof(arr)`, tetapi dengan menambahkan keamanan `ARRAY_SIZE` konstruksi. Contoh penggunaan:
batal foo(ptrdiff_t nmemb)
{
int arr[nmemb];
memset(arr, 0, ARRAY_BYTES(arr));
}
`memset()` kebutuhan nilai ini sebagai argumen ketiga. Seperti sebelumnya, jika array diterima sebagai parameter (pointer), itu tidak't mengkompilasi, dan kita akan harus mengganti makro panggilan dengan nilai:
batal foo(ptrdiff_t nmemb, int arr[nmemb])
{
memset(arr, 0, sizeof(arr[0]) * nmemb);
}
``
Anda dapat menggunakan &
operator. Berikut adalah source code:
#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 ini adalah contoh output
1549216672
1549216712
---- diff----
4
The size of array a is 10