Como determino o tamanho da minha matriz em C?
Ou seja, o número de elementos que a matriz pode conter?
Como determino o tamanho da minha matriz em C?
Ou seja, o número de elementos que a matriz pode conter?
Respostas:
Sumário executivo:
int a[17];
size_t n = sizeof(a)/sizeof(a[0]);
Resposta completa:
Para determinar o tamanho da sua matriz em bytes, você pode usar o sizeof
operador:
int a[17];
size_t n = sizeof(a);
No meu computador, ints têm 4 bytes de comprimento, então n é 68.
Para determinar o número de elementos na matriz, podemos dividir o tamanho total da matriz pelo tamanho do elemento da matriz. Você poderia fazer isso com o tipo, assim:
int a[17];
size_t n = sizeof(a) / sizeof(int);
e obtenha a resposta correta (68/4 = 17), mas se o tipo de
a
alteração for alterado, você terá um erro desagradável se esquecer de alterar sizeof(int)
também.
Portanto, o divisor preferido é sizeof(a[0])
ou equivalente sizeof(*a)
, o tamanho do primeiro elemento da matriz.
int a[17];
size_t n = sizeof(a) / sizeof(a[0]);
Outra vantagem é que agora você pode facilmente parametrizar o nome da matriz em uma macro e obter:
#define NELEMS(x) (sizeof(x) / sizeof((x)[0]))
int a[17];
size_t n = NELEMS(a);
ARRAYSIZE
makro definido em WinNT.h
(que é puxado por outros cabeçalhos). Portanto, os usuários do WinAPI não precisam definir seu próprio makro.
static int a[20];
. Mas seu comentário é útil para leitores que podem não perceber a diferença entre uma matriz e um ponteiro.
O sizeof
caminho é o caminho certo se você estiver lidando com matrizes não recebidas como parâmetros. Uma matriz enviada como parâmetro para uma função é tratada como um ponteiro; portanto sizeof
, retornará o tamanho do ponteiro, em vez do tamanho da matriz.
Assim, funções internas esse método não funciona. Em vez disso, sempre passe um parâmetro adicional size_t size
indicando o número de elementos na matriz.
Teste:
#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]) ));
}
Saída (em um sistema operacional Linux de 64 bits):
sizeof of array: 28
sizeof of parameter: 8
Length of array: 7
Length of parameter: 2
Saída (em um sistema operacional Windows de 32 bits):
sizeof of array: 28
sizeof of parameter: 4
Length of array: 7
Length of parameter: 1
length of parameter:2
se apenas um ponteiro para o primeiro elemento da matriz for passado?
(sizeof array / sizeof *array)
.
Vale ressaltar que sizeof
isso não ajuda ao lidar com um valor de matriz que se deteriorou para um ponteiro: mesmo que aponte para o início de uma matriz, para o compilador é o mesmo que um ponteiro para um único elemento dessa matriz . Um ponteiro não "lembra" mais nada sobre a matriz que foi usada para inicializá-lo.
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 bits. Tudo o que o padrão diz é que valores inteiros de 0 a 127 podem ser representados e seu intervalo é de pelo menos -127 a 127 (o caractere é assinado) ou de 0 a 255 (o caracter não é assinado).
O tamanho do "truque" é a melhor maneira que conheço, com uma pequena mas (para mim, essa é uma grande irritação) importante mudança no uso de parênteses.
Como a entrada da Wikipedia deixa claro, os Cs sizeof
não são uma função; é um operador . Portanto, ele não requer parênteses em torno de seu argumento, a menos que o argumento seja um nome de tipo. Isso é fácil de lembrar, pois faz com que o argumento pareça uma expressão convertida, que também usa parênteses.
Então: se você tem o seguinte:
int myArray[10];
Você pode encontrar o número de elementos com código como este:
size_t n = sizeof myArray / sizeof *myArray;
Isso, para mim, é muito mais fácil do que a alternativa entre parênteses. Também sou a favor do uso do asterisco na parte direita da divisão, pois é mais conciso do que a indexação.
Obviamente, isso também é tempo de compilação, portanto não há necessidade de se preocupar com a divisão que afeta o desempenho do programa. Portanto, use este formulário sempre que puder.
É sempre melhor usar sizeof em um objeto real quando você tiver um, em vez de em um tipo, pois você não precisará se preocupar em cometer um erro e declarar o tipo errado.
Por exemplo, digamos que você tenha uma função que gera alguns dados como um fluxo de bytes, por exemplo, em uma rede. Vamos chamar a função send()
e fazer com que ela tome como argumento um ponteiro para o objeto a ser enviado e o número de bytes no objeto. Então, o protótipo se torna:
void send(const void *object, size_t size);
E então você precisa enviar um número inteiro, para codificá-lo assim:
int foo = 4711;
send(&foo, sizeof (int));
Agora, você introduziu uma maneira sutil de se dar um tiro no pé, especificando o tipo foo
em dois lugares. Se um mudar, mas o outro não, o código será quebrado. Assim, sempre faça assim:
send(&foo, sizeof foo);
Agora você está protegido. Claro, você duplica o nome da variável, mas isso tem uma alta probabilidade de quebrar de uma maneira que o compilador possa detectar, se você a alterar.
sizeof(int)
requerem instruções menores do que sizeof(foo)
?
int x = 1+1;
versus int x = (1+1);
. Aqui, os parênteses são puramente absolutamente estéticos.
sizeof
sempre será constante em C ++ e C89. Com matrizes de comprimento variável do C99, ele pode ser avaliado em tempo de execução.
sizeof
pode ser um operador, mas deve ser tratado como uma função de acordo com Linus Torvalds. Concordo. Leia seu racional aqui: lkml.org/lkml/2012/7/11/103
int size = (&arr)[1] - arr;
Confira este link para obter explicações
ptrdiff_t
. (Normalmente, no sistema de 64 bits, esse será um tipo maior que int
). Mesmo se você mudar int
para ptrdiff_t
esse código, ele ainda arr
terá um erro se ocupar mais da metade do espaço de endereço.
/3G
opção de divisão de usuário / kernel 3G / 1G, que permite que as matrizes tenham até 75% do tamanho do espaço de endereço.
foo buf1[80]; foo buf2[sizeof buf1/sizeof buf1[0]]; foo buf3[(&buf1)[1] - buf1];
como variáveis globais. buf3[]
declaração falha porque (&buf1)[1] - buf1
não é uma constante.
Você pode usar o operador sizeof, mas ele não funcionará para funções, porque terá a referência do ponteiro. Você pode fazer o seguinte para encontrar o comprimento de uma matriz:
len = sizeof(arr)/sizeof(arr[0])
Código originalmente encontrado aqui: programa C para encontrar o número de elementos em uma matriz
Se você conhece o tipo de dados da matriz, pode usar algo como:
int arr[] = {23, 12, 423, 43, 21, 43, 65, 76, 22};
int noofele = sizeof(arr)/sizeof(int);
Ou, se você não souber o tipo de dados da matriz, poderá usar algo como:
noofele = sizeof(arr)/sizeof(arr[0]);
Nota: Isso funciona apenas se a matriz não estiver definida em tempo de execução (como malloc) e a matriz não for passada em uma função. Nos dois casos, arr
(nome da matriz) é um ponteiro.
int noofele = sizeof(arr)/sizeof(int);
é apenas metade do caminho melhor que a codificação int noofele = 9;
. O uso sizeof(arr)
mantém a flexibilidade caso o tamanho da matriz mude. No entanto, sizeof(int)
precisa de uma atualização, caso o tipo de arr[]
alteração. Melhor usar sizeof(arr)/sizeof(arr[0])
mesmo se o tipo for bem conhecido. Não está claro por que usar int
for noofele
vs. size_t
, o tipo retornado por sizeof()
.
A macro ARRAYELEMENTCOUNT(x)
que todo mundo está usando avalia incorretamente . Realisticamente, isso é apenas uma questão delicada, porque você não pode ter expressões que resultem em um tipo de 'matriz'.
/* Compile as: CL /P "macro.c" */
# define ARRAYELEMENTCOUNT(x) (sizeof (x) / sizeof (x[0]))
ARRAYELEMENTCOUNT(p + 1);
Realmente avalia como:
(sizeof (p + 1) / sizeof (p + 1[0]));
Enquanto que
/* Compile as: CL /P "macro.c" */
# define ARRAYELEMENTCOUNT(x) (sizeof (x) / sizeof (x)[0])
ARRAYELEMENTCOUNT(p + 1);
Ele avalia corretamente como:
(sizeof (p + 1) / sizeof (p + 1)[0]);
Isso realmente não tem muito a ver com o tamanho das matrizes explicitamente. Acabei de notar muitos erros ao não observar verdadeiramente como o pré-processador C funciona. Você sempre quebra o parâmetro macro, e não uma expressão pode estar envolvida.
Isto está correto; meu exemplo foi ruim. Mas isso é exatamente o que deveria acontecer. Como mencionei anteriormente p + 1
, acabará como um tipo de ponteiro e invalidará toda a macro (como se você tentasse usar a macro em uma função com um parâmetro de ponteiro).
No final do dia, nesse caso em particular , a falha realmente não importa (por isso estou perdendo tempo de todos; huzzah!), Porque você não tem expressões com um tipo de 'array'. Mas, na verdade, acho importante a questão dos sutis de avaliação pré-processador.
(sizeof (x) / sizeof (*x))
?
Para matrizes multidimensionais , é um pouco mais complicado. Frequentemente, as pessoas definem constantes macro explícitas, ou seja,
#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", " " },
};
Mas essas constantes também podem ser avaliadas em tempo de compilação com 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);
Observe que esse código funciona em C e C ++. Para matrizes com mais de duas dimensões, use
sizeof(name[0][0][0])
sizeof(name[0][0][0][0])
etc., ad infinitum.
sizeof(array) / sizeof(array[0])
array
, você não precisa usar sizeof(array) / sizeof(array[0])
if array
é uma matriz de char
, unsigned char
ou signed char
- Quote from C18,6.5.3.4 / 4: "Quando sizeof é aplicado a um operando que possui o tipo char, char não assinado ou char assinado , (ou uma versão qualificada), o resultado é 1. " Nesse caso, você pode simplesmente fazer o sizeof(array)
que foi explicado na minha resposta dedicada .
Tamanho de uma matriz em 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
ainda int
com int n = sizeof (a) / sizeof (a[0]);
e nãosize_t n = sizeof (a) / sizeof (a[0]);
char a[INT_MAX + 1u];
, int n
como usadas em, int n = sizeof (a) / sizeof (a[0]);
é insuficiente (é UB). O uso size_t n = sizeof (a) / sizeof (a[0]);
não incorre nesse problema.
Eu recomendaria nunca usar sizeof
(mesmo que possa ser usado) para obter qualquer um dos dois tamanhos diferentes de uma matriz, seja em número de elementos ou em bytes, que são os dois últimos casos que mostro aqui. Para cada um dos dois tamanhos, as macros mostradas abaixo podem ser usadas para torná-lo mais seguro. A razão é tornar óbvia a intenção do código para mantenedores, ea diferença sizeof(ptr)
de sizeof(arr)
, à primeira vista (que escrito desta forma não é óbvia), de modo que os erros são então óbvio para todos a leitura do código.
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)
(definido abaixo) É necessário como o -Wsizeof-pointer-div
buggy (a partir de abril / 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__; \
} \
) \
)
Houve erros importantes em relação a este tópico: https://lkml.org/lkml/2015/9/3/428
Eu discordo da solução que Linus fornece, que é nunca usar a notação de matriz para parâmetros de funções.
Eu gosto da notação de matriz como documentação de que um ponteiro está sendo usado como uma matriz. Mas isso significa que uma solução infalível precisa ser aplicada para que seja impossível escrever um código de buggy.
A partir de uma matriz, temos três tamanhos que podemos querer saber:
O primeiro é muito simples, e não importa se estamos lidando com uma matriz ou um ponteiro, porque é feito da mesma maneira.
Exemplo de uso:
void foo(ptrdiff_t nmemb, int arr[static nmemb])
{
qsort(arr, nmemb, sizeof(arr[0]), cmp);
}
qsort()
precisa desse valor como seu terceiro argumento.
Para os outros dois tamanhos, que são o tópico da pergunta, queremos ter certeza de que estamos lidando com uma matriz e interromper a compilação, se não, porque se estivermos lidando com um ponteiro, obteremos valores errados . Quando a compilação é interrompida, poderemos ver facilmente que não estávamos lidando com uma matriz, mas com um ponteiro, e teremos que escrever o código com uma variável ou macro que armazene o tamanho da matriz. matriz atrás do ponteiro.
Esta é a mais comum e muitas respostas forneceram a macro típica ARRAY_SIZE:
#define ARRAY_SIZE(arr) (sizeof(arr) / sizeof((arr)[0]))
Como o resultado de ARRAY_SIZE é comumente usado com variáveis assinadas do tipo ptrdiff_t
, é bom definir uma variante assinada dessa macro:
#define ARRAY_SSIZE(arr) ((ptrdiff_t)ARRAY_SIZE(arr))
Matrizes com mais de PTRDIFF_MAX
membros fornecerão valores inválidos para esta versão assinada da macro, mas, ao ler C17 :: 6.5.6.9, matrizes como essa já estão brincando com fogo. Somente ARRAY_SIZE
esize_t
deve ser usado nesses casos.
Versões recentes de compiladores, como o GCC 8, avisam quando você aplica essa macro a um ponteiro, portanto é seguro (existem outros métodos para torná-lo seguro em compiladores mais antigos).
Ele funciona dividindo o tamanho em bytes de toda a matriz pelo tamanho de cada elemento.
Exemplos de uso:
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 essas funções não usassem matrizes, mas as obtivessem como parâmetros, o código anterior não seria compilado, portanto seria impossível ter um bug (dado que uma versão recente do compilador é usada ou que outro truque é usado) , e precisamos substituir a chamada de macro pelo valor:
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
é comumente usado como uma solução para o caso anterior, mas esse caso raramente é escrito com segurança, talvez por ser menos comum.
A maneira comum de obter esse valor é usar sizeof(arr)
. O problema: o mesmo que o anterior; se você tiver um ponteiro em vez de uma matriz, seu programa ficará louco.
A solução para o problema envolve o uso da mesma macro de antes, que sabemos ser segura (interrompe a compilação se aplicada a um ponteiro):
#define ARRAY_BYTES(arr) (sizeof((arr)[0]) * ARRAY_SIZE(arr))
Como funciona é muito simples: desfaz a divisão que o ARRAY_SIZE
faz; portanto, após cancelamentos matemáticos, você acaba com apenas um sizeof(arr)
, mas com a segurança adicional doARRAY_SIZE
construção.
Exemplo de uso:
void foo(ptrdiff_t nmemb)
{
int arr[nmemb];
memset(arr, 0, ARRAY_BYTES(arr));
}
memset()
precisa desse valor como seu terceiro argumento.
Como antes, se o array for recebido como um parâmetro (um ponteiro), ele não será compilado e teremos que substituir a chamada de macro pelo valor:
void foo(ptrdiff_t nmemb, int arr[nmemb])
{
memset(arr, 0, sizeof(arr[0]) * nmemb);
}
-Wsizeof-pointer-div
é de buggy :Hoje descobri que o novo aviso no GCC funciona apenas se a macro estiver definida em um cabeçalho que não seja um cabeçalho do sistema. Se você definir a macro em um cabeçalho instalado no seu sistema (normalmente /usr/local/include/
ou /usr/include/
) ( #include <foo.h>
), o compilador NÃO emitirá um aviso (tentei o GCC 9.3.0).
Então, temos #define ARRAY_SIZE(arr) (sizeof(arr) / sizeof((arr)[0]))
e queremos torná-lo seguro. Vamos precisar de _Static_assert()
extensões C11 e GCC: Declarações e declarações em expressões , __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]); \
} \
)
Agora ARRAY_SIZE()
é completamente seguro e, portanto, todos os seus derivados estarão seguros.
__arraycount()
:Libbsd fornece a macro __arraycount()
em <sys/cdefs.h>
que não é seguro porque falta um par de parênteses, mas podemos adicionar os parênteses nós mesmos, e, portanto, não precisa mesmo de escrever a divisão em nosso cabeçalho (por que nós duplicar o código que já existe? ) Essa macro é definida no cabeçalho do sistema; portanto, se a usarmos, somos forçados a usar as macros acima.
#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))
Alguns sistemas fornecem nitems()
, em <sys/param.h>
vez disso, e alguns sistemas de fornecer tanto. Você deve verificar seu sistema e usar o que possui, e talvez usar alguns condicionais do pré-processador para portabilidade e suporte aos dois.
Infelizmente, a ({})
extensão gcc não pode ser usada no escopo do arquivo. Para poder usar a macro no escopo do arquivo, a asserção estática deve estar dentro sizeof(struct {})
. Em seguida, multiplique 0
para não afetar o resultado. Uma conversão para (int)
pode ser boa para simular uma função que retorna (int)0
(nesse caso, não é necessária, mas é reutilizável para outras coisas).
#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)
) que não é mostrada em outra parte: ARRAY_BYTES(arr)
.
sizeof
, mas usar essas construções; se você quiser escrever essas construções todas as vezes, provavelmente cometerá um erro (muito comum se você copiar colar e também muito comum se você as escrever todas as vezes porque elas têm muitos parênteses) ...
sizeof
é claramente insegura (as razões estão na resposta), e não usando macros, mas usando as construções que forneci, a cada vez, é ainda mais insegura, então o único caminho a percorrer são macros.
"você introduziu uma maneira sutil de se dar um tiro no pé"
As matrizes 'nativas' C não armazenam seu tamanho. Portanto, é recomendável salvar o comprimento da matriz em uma variável / const separada e passá-lo sempre que passar na matriz, ou seja:
#define MY_ARRAY_LENGTH 15
int myArray[MY_ARRAY_LENGTH];
Você sempre deve evitar matrizes nativas (a menos que não consiga, nesse caso, cuidar do seu pé). Se você estiver escrevendo C ++, use o contêiner 'vector' do STL . "Em comparação com matrizes, elas fornecem quase o mesmo desempenho" e são muito mais úteis!
// 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
declaração.
#define SIZE_OF_ARRAY(_array) (sizeof(_array) / sizeof(_array[0]))
Se você realmente deseja fazer isso para distribuir sua matriz, sugiro implementar uma estrutura para armazenar um ponteiro para o tipo do qual você deseja uma matriz e um número inteiro representando o tamanho da matriz. Então você pode passar isso para suas funções. Apenas atribua o valor da variável da matriz (ponteiro ao primeiro elemento) a esse ponteiro. Em seguida, você pode Array.arr[i]
obter o i-ésimo elemento e usar Array.size
para obter o número de elementos na matriz.
Eu incluí algum código para você. Não é muito útil, mas você pode estendê-lo com mais recursos. Para ser sincero, no entanto, se é isso que você deseja, deve parar de usar C e usar outro idioma com esses recursos incorporados.
/* 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);
sem manipulação de estouro.
A melhor maneira é salvar essas informações, por exemplo, em uma estrutura:
typedef struct {
int *array;
int elements;
} list_s;
Implemente todas as funções necessárias, como criar, destruir, verificar a igualdade e tudo o mais que você precisa. É mais fácil passar como parâmetro.
int elements
vs. size_t elements
?
A função sizeof
retorna o número de bytes que é usado por sua matriz na memória. Se você deseja calcular o número de elementos em sua matriz, divida esse número com o sizeof
tipo de variável da matriz. Digamos que int array[10];
, se o número inteiro do tipo variável no seu computador for de 32 bits (ou 4 bytes), para obter o tamanho da sua matriz, faça o seguinte:
int array[10];
int sizeOfArray = sizeof(array)/sizeof(int);
Você pode usar o &
operador. Aqui está o código fonte:
#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;
};
Aqui está a saída da amostra
1549216672
1549216712
---- diff----
4
The size of array a is 10
ptrdiff_t
. sizeof()
resulta em size_t
. C não define qual é a classificação mais ampla ou mais alta / mesma. Portanto, o tipo de quociente ((char *)(&a+1)-(char *)a)/(sizeof(a[0]))
não é certamente size_t
e, portanto, imprimir com z
pode levar a UB. Simplesmente usar printf("The size of array a is %zu\n", sizeof a/sizeof a[0]);
é suficiente.
(char *)(&a+1)-(char *)a
não é uma constante e pode ser calculado em tempo de execução, mesmo com um tamanho fixo a[10]
. sizeof(a)/sizeof(a[0])
é constante feito em tempo de compilação neste caso.
Uma solução mais elegante será
size_t size = sizeof(a) / sizeof(*a);
Além das respostas já fornecidas, quero destacar um caso especial pelo uso de
sizeof(a) / sizeof (a[0])
Se a
é ou um conjunto de char
, unsigned char
ou signed char
você não precisa usar sizeof
duas vezes desde a sizeof
expressão com um operando destes tipos sempre resultam para 1
.
Citação de C18,6.5.3.4 / 4:
" Quando
sizeof
é aplicada a um operando que tem o tipochar
,unsigned char
ousigned char
, (ou uma versão dos mesmos qualificado) o resultado é1
."
Assim, sizeof(a) / sizeof (a[0])
seria equivalente a NUMBER OF ARRAY ELEMENTS / 1
se a
é uma matriz do tipo char
, unsigned char
ou signed char
. A divisão até 1 é redundante.
Nesse caso, você pode simplesmente abreviar e fazer:
sizeof(a)
Por exemplo:
char a[10];
size_t length = sizeof(a);
Se você quer uma prova, aqui está um link para o GodBolt .
No entanto, a divisão mantém a segurança, se o tipo mudar significativamente (embora esses casos sejam raros).
Nota: Este pode fornecer um comportamento indefinido, conforme apontado por MM no comentário.
int a[10];
int size = (*(&a+1)-a) ;
*
operador não pode ser aplicado a um ponteiro passado
*(&a+1) - a;
está dizendo que é diferente do que está (&a)[1] - a;
acima, não conte *(&a+1)
e (&a)[1]
conte como 1 após o final?
x[y]
é definido como*(x + (y))