Come posso determinare la dimensione del mio array in C?
Cioè, il numero di elementi che l'array può contenere?
Come posso determinare la dimensione del mio array in C?
Cioè, il numero di elementi che l'array può contenere?
Risposte:
Sintesi:
int a[17];
size_t n = sizeof(a)/sizeof(a[0]);
Risposta completa:
Per determinare la dimensione dell'array in byte, è possibile utilizzare l' sizeof
operatore:
int a[17];
size_t n = sizeof(a);
Sul mio computer, gli ints sono lunghi 4 byte, quindi n è 68.
Per determinare il numero di elementi nell'array, possiamo dividere la dimensione totale dell'array per la dimensione dell'elemento dell'array. Puoi farlo con il tipo, in questo modo:
int a[17];
size_t n = sizeof(a) / sizeof(int);
e ottieni la risposta corretta (68/4 = 17), ma se il tipo di
a
modifica avresti un brutto bug se ti dimenticassi di cambiare ilsizeof(int)
anche quella.
Quindi il divisore preferito è sizeof(a[0])
o l'equivalente sizeof(*a)
, la dimensione del primo elemento dell'array.
int a[17];
size_t n = sizeof(a) / sizeof(a[0]);
Un altro vantaggio è che ora puoi facilmente parametrizzare il nome dell'array in una macro e ottenere:
#define NELEMS(x) (sizeof(x) / sizeof((x)[0]))
int a[17];
size_t n = NELEMS(a);
ARRAYSIZE
makro definito in WinNT.h
(che viene richiamato da altre intestazioni). Quindi gli utenti di WinAPI non devono definire il proprio makro.
static int a[20];
. Ma il tuo commento è utile per i lettori che potrebbero non capire la differenza tra un array e un puntatore.
La sizeof
strada è la strada giusta se hai a che fare con array non ricevuti come parametri. Un array inviato come parametro a una funzione viene trattato come un puntatore, quindi sizeof
restituirà la dimensione del puntatore, anziché quella dell'array.
Pertanto, all'interno delle funzioni questo metodo non funziona. Invece, passa sempre un parametro aggiuntivo che size_t size
indica il numero di elementi nell'array.
Test:
#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 (in un sistema operativo Linux a 64 bit):
sizeof of array: 28
sizeof of parameter: 8
Length of array: 7
Length of parameter: 2
Output (in un sistema operativo Windows a 32 bit):
sizeof of array: 28
sizeof of parameter: 4
Length of array: 7
Length of parameter: 1
length of parameter:2
se viene passato solo un puntatore al primo elemento dell'array?
(sizeof array / sizeof *array)
.
Vale la pena notare che sizeof
non aiuta quando si ha a che fare con un valore di array che è decaduto in un puntatore: anche se punta all'inizio di un array, per il compilatore è lo stesso di un puntatore a un singolo elemento di quell'array . Un puntatore non "ricorda" nient'altro sull'array che è stato utilizzato per inizializzarlo.
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. Tutto ciò che dice lo standard è che possono essere rappresentati valori interi da 0 a 127 e il suo intervallo è almeno -127 a 127 (carattere è firmato) o da 0 a 255 (carattere non firmato).
La dimensione del "trucco" è il modo migliore che conosco, con una piccola ma (per me, essendo questa una grande pipì per animali domestici) un cambiamento importante nell'uso della parentesi.
Come chiarisce la voce di Wikipedia, C sizeof
non è una funzione; è un operatore . Pertanto, non richiede parentesi attorno al suo argomento, a meno che l'argomento non sia un nome di tipo. Questo è facile da ricordare, dal momento che fa apparire l'argomento come un'espressione cast, che usa anche la parentesi.
Quindi: se si dispone di quanto segue:
int myArray[10];
Puoi trovare il numero di elementi con codice come questo:
size_t n = sizeof myArray / sizeof *myArray;
Questo, secondo me, è molto più semplice dell'alternativa tra parentesi. Prediligo anche l'uso dell'asterisco nella parte destra della divisione, poiché è più conciso dell'indicizzazione.
Naturalmente, anche questo è tutto in fase di compilazione, quindi non è necessario preoccuparsi della divisione che influisce sull'esecuzione del programma. Quindi usa questo modulo ovunque tu sia.
È sempre meglio usare sizeof su un oggetto reale quando ne hai uno, piuttosto che su un tipo, da allora non devi preoccuparti di fare un errore e dichiarare il tipo sbagliato.
Ad esempio, supponiamo di avere una funzione che emette alcuni dati come un flusso di byte, ad esempio attraverso una rete. Chiamiamo la funzione send()
e facciamo in modo che argomenti come puntatore all'oggetto da inviare e il numero di byte nell'oggetto. Quindi, il prototipo diventa:
void send(const void *object, size_t size);
E quindi devi inviare un numero intero, quindi codificalo in questo modo:
int foo = 4711;
send(&foo, sizeof (int));
Ora, hai introdotto un modo sottile di spararti al piede, specificando il tipo di foo
in due punti. Se uno cambia ma l'altro no, il codice si interrompe. Quindi, fallo sempre così:
send(&foo, sizeof foo);
Adesso sei protetto. Certo, duplicate il nome della variabile, ma ciò ha un'alta probabilità di rompere in un modo che il compilatore può rilevare, se lo cambiate.
sizeof(int)
richiede istruzioni minore rispetto sizeof(foo)
?
int x = 1+1;
contro int x = (1+1);
. Qui, le parentesi sono puramente assolutamente estetiche.
sizeof
sarà sempre costante in C ++ e C89. Con gli array a lunghezza variabile di C99, può essere valutato in fase di esecuzione.
sizeof
può essere un operatore ma dovrebbe essere trattato come una funzione secondo Linus Torvalds. Sono d'accordo. Leggi qui il suo razionale: lkml.org/lkml/2012/7/11/103
int size = (&arr)[1] - arr;
Dai un'occhiata a questo link per una spiegazione
ptrdiff_t
. (In genere sul sistema a 64 bit, questo sarà un tipo più grande di int
). Anche se si modifica int
a ptrdiff_t
questo codice, ha ancora un bug se arr
occupa più della metà dello spazio di indirizzamento.
/3G
opzione di suddivisione utente / kernel 3G / 1G, che consente di avere dimensioni di array fino al 75% delle dimensioni dello spazio di indirizzi.
foo buf1[80]; foo buf2[sizeof buf1/sizeof buf1[0]]; foo buf3[(&buf1)[1] - buf1];
come variabili globali. buf3[]
la dichiarazione non riesce poiché (&buf1)[1] - buf1
non è una costante.
È possibile utilizzare l'operatore sizeof ma non funzionerà per le funzioni perché prenderà il riferimento del puntatore e si può fare quanto segue per trovare la lunghezza di un array:
len = sizeof(arr)/sizeof(arr[0])
Codice originariamente trovato qui: programma C per trovare il numero di elementi in un array
Se conosci il tipo di dati dell'array, puoi usare qualcosa del tipo:
int arr[] = {23, 12, 423, 43, 21, 43, 65, 76, 22};
int noofele = sizeof(arr)/sizeof(int);
Oppure, se non conosci il tipo di dati dell'array, puoi usare qualcosa come:
noofele = sizeof(arr)/sizeof(arr[0]);
Nota: questa cosa funziona solo se l'array non è definito in fase di esecuzione (come malloc) e l'array non viene passato in una funzione. In entrambi i casi, arr
(nome della matrice) è un puntatore.
int noofele = sizeof(arr)/sizeof(int);
è solo a metà strada migliore della codifica int noofele = 9;
. L'utilizzo sizeof(arr)
mantiene la flessibilità in caso di modifica delle dimensioni dell'array. Tuttavia ha sizeof(int)
bisogno di un aggiornamento se il tipo di arr[]
modifica. Meglio usare sizeof(arr)/sizeof(arr[0])
anche se il tipo è ben noto. Non è chiaro il motivo int
per cui usando for noofele
vs. size_t
, il tipo restituito da sizeof()
.
La macro utilizzata ARRAYELEMENTCOUNT(x)
da tutti viene valutata in modo errato . Questo, realisticamente, è solo una questione delicata, perché non è possibile avere espressioni che generano un tipo "array".
/* Compile as: CL /P "macro.c" */
# define ARRAYELEMENTCOUNT(x) (sizeof (x) / sizeof (x[0]))
ARRAYELEMENTCOUNT(p + 1);
In realtà valuta come:
(sizeof (p + 1) / sizeof (p + 1[0]));
Mentre
/* Compile as: CL /P "macro.c" */
# define ARRAYELEMENTCOUNT(x) (sizeof (x) / sizeof (x)[0])
ARRAYELEMENTCOUNT(p + 1);
Valuta correttamente a:
(sizeof (p + 1) / sizeof (p + 1)[0]);
Questo non ha molto a che fare con la dimensione delle matrici esplicitamente. Ho appena notato molti errori nel non osservare veramente come funziona il preprocessore C. Avvolgi sempre il parametro macro, in cui non potrebbe essere coinvolta un'espressione.
Questo è corretto; il mio esempio è stato negativo. Ma questo è esattamente ciò che dovrebbe accadere. Come ho già dettop + 1
finirà come un tipo di puntatore e invaliderà l'intera macro (proprio come se si tentasse di utilizzare la macro in una funzione con un parametro puntatore).
Alla fine della giornata, in questo caso particolare , la colpa non ha molta importanza (quindi sto solo sprecando il tempo di tutti; huzzah!), Perché non hai espressioni con un tipo di "array". Ma in realtà il punto sui sottotitoli di valutazione del preprocessore penso sia importante.
(sizeof (x) / sizeof (*x))
?
Per gli array multidimensionali è un po 'più complicato. Spesso le persone definiscono costanti macro esplicite, vale a dire
#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", " " },
};
Ma queste costanti possono essere valutate anche in fase di compilazione con 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);
Si noti che questo codice funziona in C e C ++. Per array con più di due dimensioni utilizzare
sizeof(name[0][0][0])
sizeof(name[0][0][0][0])
ecc. all'infinito.
sizeof(array) / sizeof(array[0])
array
, non è necessario utilizzare sizeof(array) / sizeof(array[0])
se array
è una matrice di uno dei due char
, unsigned char
oppure signed char
- Citazione da C18,6.5.3.4 / 4: "Quando sizeof viene applicato a un operando che ha tipo char, unsigned char, o char char , (o una sua versione qualificata) il risultato è 1. " In questo caso puoi semplicemente fare sizeof(array)
come spiegato nella mia risposta dedicata .
Dimensione di un array in 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
ancora int
con int n = sizeof (a) / sizeof (a[0]);
e nonsize_t n = sizeof (a) / sizeof (a[0]);
char a[INT_MAX + 1u];
, int n
usato in int n = sizeof (a) / sizeof (a[0]);
è insufficiente (è UB). L'uso size_t n = sizeof (a) / sizeof (a[0]);
non comporta questo problema.
Consiglio di non usare mai sizeof
(anche se può essere usato) per ottenere una delle due diverse dimensioni di un array, in numero di elementi o in byte, che sono gli ultimi due casi che mostro qui. Per ciascuna delle due dimensioni, le macro mostrate di seguito possono essere utilizzate per renderlo più sicuro. Il motivo è quello di rendere evidente l'intenzione del codice per manutentori, e la differenza sizeof(ptr)
da sizeof(arr)
al primo sguardo (che scritto in questo modo non è ovvio), in modo che gli insetti sono quindi evidenti per tutti la lettura del codice.
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)
(definito di seguito) È necessario come -Wsizeof-pointer-div
è buggy (da aprile / 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__; \
} \
) \
)
Ci sono stati importanti bug su questo argomento: https://lkml.org/lkml/2015/9/3/428
Non sono d'accordo con la soluzione fornita da Linus, che è quella di non usare mai la notazione di array per i parametri delle funzioni.
Mi piace la notazione di array come documentazione secondo cui un puntatore viene utilizzato come array. Ciò significa che è necessario applicare una soluzione a prova di errore, in modo che sia impossibile scrivere codice errato.
Da un array abbiamo tre dimensioni che potremmo voler sapere:
Il primo è molto semplice e non importa se abbiamo a che fare con un array o un puntatore, perché è fatto allo stesso modo.
Esempio di utilizzo:
void foo(ptrdiff_t nmemb, int arr[static nmemb])
{
qsort(arr, nmemb, sizeof(arr[0]), cmp);
}
qsort()
ha bisogno di questo valore come terzo argomento.
Per le altre due dimensioni, che sono l'argomento della domanda, vogliamo assicurarci di avere a che fare con un array e, in caso contrario, interrompere la compilazione, perché se abbiamo a che fare con un puntatore, avremo valori errati . Quando la compilazione viene interrotta, saremo in grado di vedere facilmente che non avevamo a che fare con un array, ma con un puntatore, e dovremo solo scrivere il codice con una variabile o una macro che memorizza la dimensione del matrice dietro il puntatore.
Questo è il più comune e molte risposte ti hanno fornito la tipica macro ARRAY_SIZE:
#define ARRAY_SIZE(arr) (sizeof(arr) / sizeof((arr)[0]))
Dato che il risultato di ARRAY_SIZE è comunemente usato con variabili di tipo firmate ptrdiff_t
, è bene definire una variante firmata di questa macro:
#define ARRAY_SSIZE(arr) ((ptrdiff_t)ARRAY_SIZE(arr))
Le matrici con più di PTRDIFF_MAX
membri daranno valori non validi per questa versione firmata della macro, ma dalla lettura di C17 :: 6.5.6.9, matrici del genere stanno già giocando con il fuoco. Solo ARRAY_SIZE
esize_t
dovrebbe essere usato in questi casi.
Le versioni recenti dei compilatori, come GCC 8, ti avviseranno quando applichi questa macro a un puntatore, quindi è sicuro (ci sono altri metodi per renderlo sicuro con compilatori più vecchi).
Funziona dividendo la dimensione in byte dell'intero array per la dimensione di ciascun elemento.
Esempi di utilizzo:
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;
}
Se queste funzioni non usassero le matrici, ma le ottenessero invece come parametri, il codice precedente non verrebbe compilato, quindi sarebbe impossibile avere un bug (dato che viene utilizzata una versione recente del compilatore o che viene utilizzato qualche altro trucco) e dobbiamo sostituire la chiamata macro con il valore:
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
è comunemente usato come soluzione al caso precedente, ma questo caso è raramente scritto in modo sicuro, forse perché è meno comune.
Il modo comune per ottenere questo valore è usare sizeof(arr)
. Il problema: lo stesso del precedente; se hai un puntatore invece di un array, il tuo programma diventerà pazzo.
La soluzione al problema consiste nell'utilizzare la stessa macro di prima, che sappiamo essere sicura (interrompe la compilazione se viene applicata a un puntatore):
#define ARRAY_BYTES(arr) (sizeof((arr)[0]) * ARRAY_SIZE(arr))
Come funziona è molto semplice: annulla la divisione che lo ARRAY_SIZE
fa, quindi dopo le cancellazioni matematiche si finisce con una sola sizeof(arr)
, ma con la sicurezza aggiuntiva della ARRAY_SIZE
costruzione.
Esempio di utilizzo:
void foo(ptrdiff_t nmemb)
{
int arr[nmemb];
memset(arr, 0, ARRAY_BYTES(arr));
}
memset()
ha bisogno di questo valore come terzo argomento.
Come prima, se l'array viene ricevuto come parametro (un puntatore), non verrà compilato e dovremo sostituire la chiamata macro con il valore:
void foo(ptrdiff_t nmemb, int arr[nmemb])
{
memset(arr, 0, sizeof(arr[0]) * nmemb);
}
-Wsizeof-pointer-div
buggy :Oggi ho scoperto che il nuovo avviso in GCC funziona solo se la macro è definita in un'intestazione che non è un'intestazione del sistema. Se definisci la macro in un'intestazione installata nel tuo sistema (di solito /usr/local/include/
o /usr/include/
) ( #include <foo.h>
), il compilatore NON emetterà un avviso (ho provato GCC 9.3.0).
Quindi abbiamo #define ARRAY_SIZE(arr) (sizeof(arr) / sizeof((arr)[0]))
e vogliamo renderlo sicuro. Avremo bisogno di C11 _Static_assert()
e di alcune estensioni GCC: dichiarazioni e dichiarazioni in espressioni , __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]); \
} \
)
Ora ARRAY_SIZE()
è completamente sicuro e quindi tutti i suoi derivati saranno al sicuro.
__arraycount()
:Libbsd fornisce la macro __arraycount()
in <sys/cdefs.h>
, che non è sicura perché manca una coppia di parentesi, ma possiamo aggiungere noi stessi quelle parentesi, e quindi non abbiamo nemmeno bisogno di scrivere la divisione nella nostra intestazione (perché dovremmo duplicare il codice che già esiste? ). Quella macro è definita in un'intestazione del sistema, quindi se la usiamo siamo costretti a usare le macro sopra.
#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))
Alcuni sistemi forniscono nitems()
a <sys/param.h>
posto, e alcuni sistemi forniscono sia. Dovresti controllare il tuo sistema e usare quello che hai, e forse usare alcuni condizionali del preprocessore per la portabilità e il supporto di entrambi.
Sfortunatamente, l' ({})
estensione gcc non può essere usata nell'ambito dei file. Per poter utilizzare la macro nell'ambito del file, l'asserzione statica deve essere all'interno sizeof(struct {})
. Quindi, moltiplicalo 0
per non influenzare il risultato. Un cast (int)
potrebbe essere utile per simulare una funzione che ritorna (int)0
(in questo caso non è necessario, ma è riutilizzabile per altre cose).
#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)
) che non è mostrato altrove ARRAY_BYTES(arr)
.
sizeof
, ma usare invece queste costruzioni; se hai voglia di scrivere queste costruzioni ogni volta, probabilmente commetterai un errore (molto comune se copi incolla, e anche molto comune se le scrivi ogni volta perché hanno molte parentesi) ...
sizeof
è chiaramente non sicuro (i motivi sono nella risposta), e non usare le macro ma usare le costruzioni che ho fornito, ogni volta, è ancora più pericoloso, quindi l'unico modo per andare sono le macro.
"hai introdotto un modo sottile di spararti al piede"
Le matrici "native" non memorizzano le loro dimensioni. Si consiglia pertanto di salvare la lunghezza dell'array in una variabile / const separata e passarla ogni volta che si passa all'array, ovvero:
#define MY_ARRAY_LENGTH 15
int myArray[MY_ARRAY_LENGTH];
DOVREBBE sempre evitare le matrici native (a meno che non sia possibile, nel qual caso, badare al piede). Se stai scrivendo C ++, usa il contenitore "vector" di STL . "Rispetto agli array, offrono quasi le stesse prestazioni" e sono molto più utili!
// 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
dichiarazione.
#define SIZE_OF_ARRAY(_array) (sizeof(_array) / sizeof(_array[0]))
Se vuoi davvero farlo per passare intorno alla tua matrice, ti suggerisco di implementare una struttura per memorizzare un puntatore al tipo di cui desideri una matrice e un numero intero che rappresenti la dimensione della matrice. Quindi puoi passarlo alle tue funzioni. Basta assegnare il valore della variabile di matrice (puntatore al primo elemento) a quel puntatore. Quindi puoi andare Array.arr[i]
per ottenere l'i-esimo elemento e usare Array.size
per ottenere il numero di elementi nell'array.
Ho incluso del codice per te. Non è molto utile ma potresti estenderlo con più funzionalità. Ad essere onesti, se queste sono le cose che desideri, dovresti smettere di usare C e usare un'altra lingua con queste funzionalità integrate.
/* 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);
gestito senza overflow.
Il modo migliore è salvare queste informazioni, ad esempio in una struttura:
typedef struct {
int *array;
int elements;
} list_s;
Implementa tutte le funzioni necessarie come creare, distruggere, verificare l'uguaglianza e tutto ciò di cui hai bisogno. È più facile passare come parametro.
int elements
vs. size_t elements
?
La funzione sizeof
restituisce il numero di byte utilizzato dall'array in memoria. Se si desidera calcolare il numero di elementi nell'array, è necessario dividere tale numero con il sizeof
tipo variabile dell'array. Diciamo che int array[10];
se il numero intero di tipo variabile nel tuo computer è a 32 bit (o 4 byte), per ottenere la dimensione dell'array, dovresti fare quanto segue:
int array[10];
int sizeOfArray = sizeof(array)/sizeof(int);
Puoi usare l' &
operatore. Ecco il codice sorgente:
#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;
};
Ecco l'output di esempio
1549216672
1549216712
---- diff----
4
The size of array a is 10
ptrdiff_t
. sizeof()
risultati in size_t
. C non definisce quale sia il grado più ampio o più alto / lo stesso. Quindi il tipo di quoziente ((char *)(&a+1)-(char *)a)/(sizeof(a[0]))
non è certo size_t
e quindi la stampa con z
può portare a UB. Basta usare printf("The size of array a is %zu\n", sizeof a/sizeof a[0]);
è sufficiente.
(char *)(&a+1)-(char *)a
non è una costante e può essere calcolata in fase di esecuzione, anche con dimensioni fisse a[10]
. sizeof(a)/sizeof(a[0])
in questo caso viene eseguito costantemente al momento della compilazione.
Una soluzione più elegante sarà
size_t size = sizeof(a) / sizeof(*a);
Oltre alle risposte già fornite, voglio evidenziare un caso speciale con l'uso di
sizeof(a) / sizeof (a[0])
Se a
è una matrice di char
, unsigned char
o signed char
non è necessario utilizzarla sizeof
due volte poiché sizeof
risulta sempre un'espressione con un operando di questi tipi 1
.
Citazione da C18,6.5.3.4 / 4:
" Quando
sizeof
viene applicato a un operando che ha tipochar
,unsigned char
osigned char
, (o una sua versione qualificata) il risultato è1
."
Pertanto, sizeof(a) / sizeof (a[0])
sarebbe equivalente a NUMBER OF ARRAY ELEMENTS / 1
if a
è una matrice di tipo char
, unsigned char
oppure signed char
. La divisione per 1 è ridondante.
In questo caso, puoi semplicemente abbreviare e fare:
sizeof(a)
Per esempio:
char a[10];
size_t length = sizeof(a);
Se vuoi una prova, ecco un link a GodBolt .
Tuttavia, la divisione mantiene la sicurezza, se il tipo cambia significativamente (anche se questi casi sono rari).
Nota: questo può darti un comportamento indefinito come indicato da MM nel commento.
int a[10];
int size = (*(&a+1)-a) ;
*
operatore non può essere applicato a un puntatore oltre la fine
*(&a+1) - a;
è diverso da (&a)[1] - a;
sopra, non entrambi *(&a+1)
e (&a)[1]
contano come 1 dopo la fine?
x[y]
è definito come*(x + (y))