variable una tamaño que puntero programacion matriz matrices doble dinamica con cadena c visual-studio const pointer-conversion

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* .