una - matriz dinamica java
Tipo adecuado para una matriz dinámica de cadenas de const. (2)
Siempre tuve la impresión de que const char **x
era el tipo correcto que se usaba para una matriz de constantes asignada dinámicamente, como por ejemplo:
#include <stdlib.h>
int main()
{
const char **arr = malloc(10 * sizeof(const char *));
const char *str = "Hello!";
arr[0] = str;
free(arr);
}
Sin embargo, al compilar este código con VS2017, recibo esta advertencia en la línea free
:
warning C4090: ''function'': different ''const'' qualifiers
¿Hay algo mal con mi código? FWIW, cuando compilo con GCC, no recibo ninguna advertencia, incluso con -Wall -Wextra -pedantic
.
La asignación es válida por la misma razón que la siguiente asignación es válida.
const char** arr = malloc(10 * sizeof(const char *));
void* p = arr;
Esta regla 1 explica que, si los dos operandos son tipos de puntero, el puntero del tipo a la izquierda apunta a, debe tener los mismos calificadores, como el tipo al que apunta el puntero derecho.
El operando correcto es un puntero que apunta a un tipo que no tiene ningún calificador. Este tipo es un puntero de tipo para un carácter const char*
( const char*
). No dejes que el calificador const te confunda, ese calificador no pertenece al tipo de puntero.
El operando de la izquierda es un puntero que apunta a un tipo que tampoco tiene calificadores. El tipo se anula. Así que la asignación es válida.
Si el puntero está apuntando a un tipo que tiene calificadores, la asignación no sería válida:
const char* const* arr = malloc(10 * sizeof(const char *));
void* p = arr; //constraint violation
El operando derecho es un puntero que apunta a un tipo con el calificador const, este tipo es un puntero de tipo const a un carácter const char* const
( const char* const
).
El operando de la izquierda es un puntero que apunta a un tipo sin calificadores, este tipo se anula. La asignación viola la restricción 1 .
1 (Citado de: ISO / IEC 9899: 201x 6.5.16.1 Restricciones de asignación simple 1)
el operando de la izquierda tiene un tipo de puntero atómico, calificado o no calificado y (considerando el tipo que tendría el operando de la izquierda después de la conversión de valores) un operando es un puntero a un tipo de objeto, y el otro es un puntero a una versión calificada o no calificada de nulo, y el tipo apuntado por la izquierda tiene todos los calificadores del tipo apuntado por la derecha;
No hay nada malo con su código. Las reglas para esto se encuentran en el estándar C aquí:
6.3.2.3 Punteros
Un puntero para anular se puede convertir ao desde un puntero a cualquier tipo de objeto. Un puntero a cualquier tipo de objeto se puede convertir en un puntero para anularlo y viceversa; El resultado se comparará igual al puntero original.Para cualquier calificador q, un puntero a un tipo no calificado por q puede convertirse en un puntero a la versión calificada por q del tipo; Los valores almacenados en los punteros originales y convertidos se compararán igual.
Lo que significa que cualquier puntero al tipo de objeto (a una variable) se puede convertir en un puntero de vacío, a menos que el puntero esté calificado (constante o volátil). Así que está bien hacer
void* vp;
char* cp;
vp = cp;
Pero no está bien hacer
void* vp;
const char* cp;
vp = cp; // not an allowed form of pointer conversion
Hasta ahora tan bueno. Pero cuando mezclamos punteros a punteros, la constancia es un tema muy confuso.
Cuando tenemos un const char** arr
, tenemos un puntero para apuntar a constante char (pista: lea la expresión de derecha a izquierda). O, en C estándar gibberish: un puntero a un puntero calificado para escribir. arr
sí mismo no es un puntero calificado aunque! Sólo apunta a uno.
free()
espera que un puntero se anule. Podemos pasarle cualquier tipo de puntero a menos que pasemos un puntero calificado. const char**
no es un puntero calificado, por lo que podemos pasarlo bien.
Un puntero calificado para apuntar al tipo habría sido char* const*
.
Observe cómo gcc se queja cuando intentamos esto:
char*const* arr = malloc(10 * sizeof(char*const*));
free(arr);
gcc -std=c11 -pedantic-errors -Wall - Wextra
:
error: pasar el argumento 1 del calificador ''const'' ''libre'' del indicador de tipo de destino
Al parecer, Visual Studio da un diagnóstico incorrecto. O alternativamente, compiló el código como C ++, que no permite conversiones implícitas a / from void*
.