punteros - C literales compuestos, puntero a matrices
punteros y matrices en c (5)
Como nadie lo dijo: si quieres tener un puntero-a-2D-array, puedes (probablemente) hacer algo como
int (*p)[][3] = &(int[][3]) {{1,2,3},{4,5,6}};
EDITAR: O puede tener un puntero a su primer elemento a través de
int (*p)[3] = (int[][3]) {{1,2,3},{4,5,6}};
La razón por la cual su ejemplo no funciona es porque {{1,2,3},{4,5,6}}
no es un inicializador válido para tipo int*[]
(porque {1,2,3}
no es un inicializador válido para int*
). Tenga en cuenta que no es un int[2][3]
; es simplemente una expresión inválida.
La razón por la que funciona para cadenas es porque "one"
es un inicializador válido para char[]
y char[N]
(para algunos N> 3). Como expresión , es aproximadamente equivalente a (const char[]){''o'',''n'',''e'',''/0''}
excepto que el compilador no se queja demasiado cuando pierde la consistencia.
Y sí, hay una gran diferencia entre un inicializador y una expresión. Estoy bastante seguro de que char s[] = (char[]){3,2,1,0};
es un error de compilación en C99 (y posiblemente en C ++ pre-0x). También hay muchas otras cosas, pero T foo = ...;
es la inicialización variable, no la asignación, aunque parezcan similares. (Son especialmente diferentes en C ++, ya que no se llama al operador de asignación).
Y la razón de la confusión con los punteros:
- El tipo
T[]
se convierte implícitamente a tipoT*
(un puntero a su primer elemento) cuando es necesario. -
T arg1[]
en una lista de argumentos de funciones significa realmenteT * arg1
. No puede pasar una matriz a una función por Varias razones. No es posible. Si lo intenta, en realidad está pasando un puntero a matriz. (Sin embargo, puede pasar una estructura que contenga una matriz de tamaño fijo a una función). - Ambos pueden ser desreferenciados y subscriptos con semántica idéntica (creo).
EDITAR: El observador puede notar que mi primer ejemplo es aproximadamente sintácticamente equivalente a int * p = &1;
, que no es válido Esto funciona en C99 porque un literal compuesto dentro de una función "tiene una duración de almacenamiento automática asociada con el bloque envolvente" ( ISO / IEC 9899: TC3 ).
Intento asignar un literal compuesto a una variable, pero parece que no funciona, ver:
int *p[] = (int *[]) {{1,2,3},{4,5,6}};
Recibí un error en gcc.
pero si escribo solo esto:
int p[] = (int []) {1,2,3,4,5,6};
Entonces está bien.
Pero no es lo que quiero
No entiendo por qué ocurre el error, porque si lo inicializo como una matriz, o lo uso con un puntero de matrices de caracteres, está bien, mira:
int *p[] = (int *[]) {{1,2,3},{4,5,6}}; //I got a error
int p[][3] = {{1,2,3},{4,5,6}}; //it''s okay
char *p[] = (char *[]) {"one", "two"...}; // it''s okay!
Tenga en cuenta que no entiendo por qué recibí un error en el primero, y por favor, no puedo, o no quiero escribir como el segundo formulario porque debe ser un compuesto literales, y no quiero para decir qué tan grande es la matriz para el compilador. Quiero algo como el segundo, pero para valores int.
Gracias por adelantado.
El que estás usando es una matriz de punteros int. Deberías usar el puntero a la matriz:
int (*p)[] = (int *) {{1,2,3}, {4,5,6}}
Mire this respuesta para más detalles.
En primer lugar, los moldes son redundantes en todos sus ejemplos y se pueden eliminar. En segundo lugar, está utilizando la sintaxis para inicializar una matriz multidimensional, y eso requiere que se defina la segunda dimensión para asignar un bloque de memoria secuencial. En su lugar, pruebe uno de los dos enfoques a continuación:
Matriz multidimensional:
int p[][3] = {{1,2,3},{4,5,6}};
Matriz de punteros a matrices unidimensionales:
int p1[] = {1,2,3}; int p2[] = {4,5,6}; int *p[] = {p1,p2};
El último método tiene la ventaja de permitir sub-arrays de longitud variable. Mientras que el primer método asegura que la memoria se distribuye contiguamente.
Otro enfoque que recomiendo que NO use es codificar los enteros en literales de cadenas. Este es un truco no portátil. Además, se supone que los datos en los literales de cadena son constantes. ¿Sus matrices deben ser mutables?
int *p[] = (int *[]) {
"/x01/x00/x00/x00/x02/x00/x00/x00/x03/x00/x00/x00",
"/x04/x00/x00/x00/x05/x00/x00/x00/x06/x00/x00/x00"
};
Ese ejemplo podría funcionar en una máquina little-endian de 32 bits, pero estoy escribiendo esto desde un iPad y no puedo verificarlo en este momento. Nuevamente, por favor no lo uses; Me siento sucio por siquiera mencionarlo.
El método de conversión que descubrió también parece funcionar con un puntero a un puntero. Eso también se puede indexar como una matriz multidimensional.
int **p = (int *[]) { (int[]) {1,2,3}, (int[]) {4,5,6} };
Parece que estás confundiendo punteros y matriz. ¡No son lo mismo! Una matriz es la lista en sí, mientras que un puntero es solo una dirección. Luego, con la aritmética del puntero puede pretender que los punteros son una matriz, y con el hecho de que el nombre de una matriz es un puntero al primer elemento, todo se resume en un lío. ;)
int *p[] = (int *[]) {{1,2,3},{4,5,6}}; //I got a error
Aquí, p es una matriz de punteros, por lo que está intentando asignar los elementos cuyas direcciones son 1, 2, 3 a la primera matriz y 4, 5, 6 a la segunda matriz. La falla seg se debe a que no puede acceder a esas ubicaciones de memoria.
int p[][3] = {{1,2,3},{4,5,6}}; //it''s okay
Esto está bien porque es una matriz de matrices, por lo que esta vez 1, 2, 3, 4, 5 y 6 no son direcciones sino los elementos mismos.
char *p[] = (char *[]) {"one", "two"...}; // it''s okay!
Esto está bien porque los literales de cadena ("uno", "dos", ...) no son realmente cadenas sino punteros a esas cadenas, por lo que está asignando a p [1] la dirección del literal de cadena "uno" .
Por cierto, esto es lo mismo que hacer char abc[]; abc = "abc";
char abc[]; abc = "abc";
. Esto no compilará, porque no puede asignar un puntero a una matriz, mientras que char *def; def = "def";
char *def; def = "def";
resuelve el problema
Primero comprende que "las matrices no son punteros".
int p[] = (int []) {1,2,3,4,5,6};
En el caso anterior, p
es una matriz de números enteros. Copiando los elementos {1,2,3,4,5,6}
a p
. En este caso, no es necesario el rvalue
y tanto los tipos rvalue
como rvalue
coinciden, que es una matriz de enteros y, por lo tanto, no hay ningún error.
int *p[] = (int *[]) {{1,2,3},{4,5,6}};
"Nota que no entiendo por qué recibí un error en el primero, ..."
En el caso anterior, p
una matriz de punteros enteros. Pero {{1,2,3},{4,5,6}}
es una matriz bidimensional (es decir, [] []) y no se puede convertir en una matriz de punteros. Necesita inicializar como -
int p[][3] = { {1,2,3},{4,5,6} };
// ^^ First index of array is optional because with each column having 3 elements
// it is obvious that array has two rows which compiler can figure out.
Pero ¿por qué esta declaración compila?
char *p[] = {"one", "two"...};
Los literales de cadena son diferentes de los literales enteros. En este caso también, p
es una matriz de punteros de caracteres. Cuando en realidad dice "one"
, puede copiarse en una matriz o señalar su ubicación, considerándolo como de solo lectura .
char cpy[] = "one" ;
cpy[0] = ''t'' ; // Not a problem
char *readOnly = "one" ;
readOnly[0] = ''t'' ; // Error because of copy of it is not made but pointing
// to a read only location.
Con los literales de cadena, cualquiera de los casos anteriores es posible. Entonces, esa es la razón por la cual compiló la declaración. Pero -
char *p[] = {"one", "two"...}; // All the string literals are stored in
// read only locations and at each of the array index
// stores the starting index of each string literal.
No quiero decir qué tan grande es la matriz para el compilador.
Asignar dinámicamente la memoria con malloc
es la solución.
Espero eso ayude !