una segmentation segmentacion psicografico psicograficas psicografica productos producto primaria perfil palabras mercado generado empresa ejemplos ejemplo consumidor caracteristicas c arrays pointers

segmentation - "Int*nums={5, 2, 1, 4}" provoca un error de segmentación



segmentacion psicografica ejemplos de productos (5)

int *nums = {5, 2, 1, 4}; printf("%d/n", nums[0]);

causa un defecto de seguridad, mientras que

int nums[] = {5, 2, 1, 4}; printf("%d/n", nums[0]);

no lo hace Ahora:

int *nums = {5, 2, 1, 4}; printf("%d/n", nums);

impresiones 5.

En base a esto, he conjeturado que la notación de inicialización de matriz, {}, carga ciegamente estos datos en cualquier variable que esté a la izquierda. Cuando es int [], la matriz se llena como se desee. Cuando es int *, el puntero se llena con 5, y las ubicaciones de memoria después de donde se almacena el puntero se llenan con 2, 1 y 4. Por lo tanto, nums [0] intenta eliminar 5, causando una falla por defecto.

Si me equivoco, corrígeme. Y si estoy en lo correcto, explique, porque no entiendo por qué los inicializadores de matriz funcionan de la manera en que lo hacen.


Al asignar {5, 2, 1, 4}

int *nums = {5, 2, 1, 4};

está asignando 5 a nums (después de una conversión implícita de int a puntero a int). Si lo desmarca, realiza una llamada de acceso a la ubicación de memoria en 0x5 . Es posible que su programa no pueda acceder.

Tratar

printf("%p", (void *)nums);


Hay una regla (estúpida) en C que dice que cualquier variable simple puede inicializarse con una lista de inicializadores encerrada entre llaves, como si fuera una matriz.

Por ejemplo, puede escribir int x = {0}; , que es completamente equivalente a int x = 0; .

Entonces, cuando escribes int *nums = {5, 2, 1, 4}; En realidad, está dando una lista de inicializador a una sola variable de puntero. Sin embargo, es solo una variable única, por lo que solo se le asignará el primer valor 5, el resto de la lista se ignora (en realidad no creo que el código con un exceso de inicializadores incluso se compile con un compilador estricto), no escribir en la memoria en absoluto. El código es equivalente a int *nums = 5; . Lo que significa que los nums deben apuntar a la dirección 5 .

En este punto, ya debería haber recibido dos advertencias / errores del compilador:

  • Asignación de un entero al puntero sin un reparto.
  • Elementos en exceso en la lista de inicializadores.

Y luego, por supuesto, el código se bloqueará y quemará, ya que 5 probablemente no sea una dirección válida a la que se le permite desreferenciar con nums[0] .

Como nota al margen, debe printf direcciones de puntero printf con el especificador %p o, de lo contrario, está invocando un comportamiento indefinido.

No estoy muy seguro de lo que está intentando hacer aquí, pero si desea establecer un puntero para apuntar a una matriz, debe hacer lo siguiente:

int nums[] = {5, 2, 1, 4}; int* ptr = nums; // or equivalent: int* ptr = (int[]){5, 2, 1, 4};

O si desea crear una matriz de punteros:

int* ptr[] = { /* whatever makes sense here */ };

EDITAR

Después de algunas investigaciones, puedo decir que la "lista de inicializadores de elementos excedentes" no es válida C, es una extensión GCC .

La inicialización estándar 6.7.9 dice (el énfasis es mío):

2 Ningún inicializador intentará proporcionar un valor para un objeto no contenido dentro de la entidad que se está inicializando.

/ - /

11 El inicializador para un escalar debe ser una sola expresión, opcionalmente encerrada entre llaves. El valor inicial del objeto es el de la expresión (después de la conversión); se aplican las mismas restricciones de tipo y conversiones que para la asignación simple, tomando el tipo del escalar como la versión no calificada de su tipo declarado.

"Tipo escalar" es un término estándar que se refiere a variables individuales que no son del tipo matriz, estructura o unión (se denominan "tipo agregado").

Entonces, en inglés simple, el estándar dice: "cuando inicializa una variable, siéntase libre de agregar algunos corchetes adicionales alrededor de la expresión del inicializador, solo porque puede".


int *nums = {5, 2, 1, 4}; Es un código mal formado. Hay una extensión GCC que trata este código de la misma manera que:

int *nums = (int *)5;

intentando formar un puntero a la dirección de memoria 5. (Esto no me parece una extensión útil, pero supongo que la base de desarrolladores lo quiere).

Para evitar este comportamiento (o al menos obtener una advertencia), puede compilar en modo estándar, por ejemplo, -std=c11 -pedantic .

Una forma alternativa de código válido sería:

int *nums = (int[]){5, 2, 1, 4};

que apunta a un literal mutable de la misma duración de almacenamiento que nums . Sin embargo, la versión int nums[] es generalmente mejor ya que usa menos almacenamiento y puede usar sizeof para detectar cuánto dura la matriz.


ESCENARIO 1

int *nums = {5, 2, 1, 4}; // <-- assign multiple values to a pointer variable printf("%d/n", nums[0]); // segfault

¿Por qué este segfault?

Usted declaró nums como un puntero a int, es decir, se supone que nums contiene la dirección de un entero en la memoria.

Luego trató de inicializar nums en una matriz de múltiples valores. Entonces, sin profundizar en muchos detalles, esto es conceptualmente incorrecto : no tiene sentido asignar múltiples valores a una variable que se supone que contiene un valor. En este sentido, verías exactamente el mismo efecto si haces esto:

int nums = {5, 2, 1, 4}; // <-- assign multiple values to an int variable printf("%d/n", nums); // also print 5

En cualquier caso (asigne múltiples valores a un puntero o una variable int), lo que sucede entonces es que la variable obtendrá el primer valor que es 5 , mientras que los valores restantes se ignoran. Este código cumple, pero recibirá advertencias para cada valor adicional que no se supone que está en la asignación:

warning: excess elements in scalar initializer .

Para el caso de asignar múltiples valores a la variable de puntero, el programa falla cuando accede a nums[0] , lo que significa que está defendiendo lo que está almacenado en la dirección 5 literalmente. No asignó ninguna memoria válida para nums puntero en este caso.

Vale la pena señalar que no hay segfault para el caso de asignar múltiples valores a la variable int (no está haciendo referencia a ningún puntero no válido aquí).

ESCENARIO 2

int nums[] = {5, 2, 1, 4};

Este no es predeterminado, porque está asignando legalmente una matriz de 4 entradas en la pila.

ESCENARIO 3

int *nums = {5, 2, 1, 4}; printf("%d/n", nums); // print 5

Este no se divide por defecto como se esperaba, porque está imprimiendo el valor del puntero en sí , NO lo que está desreferenciando (que es el acceso no válido a la memoria).

Otros

Casi siempre está condenado a segfault cada vez que codifica el valor de un puntero como este (porque es la tarea del sistema operativo determinar qué proceso puede acceder a qué ubicación de memoria).

int *nums = 5; // <-- segfault

Por lo tanto, una regla general es siempre inicializar un puntero a la dirección de alguna variable asignada , como:

int a; int *nums = &a;

o,

int a[] = {5, 2, 1, 4}; int *nums = a;


int *nums = {5, 2, 1, 4};

nums es un puntero de tipo int . Por lo tanto, debe hacer este punto a alguna ubicación de memoria válida. num[0] intenta desreferenciar alguna ubicación de memoria aleatoria y, por lo tanto, la falla de segmentación.

Sí, el puntero tiene el valor 5 e intenta desreferenciarlo, lo cual es un comportamiento indefinido en su sistema. (Parece que 5 no es una ubicación de memoria válida en su sistema)

Mientras

int nums[] = {1,2,3,4};

es una declaración válida donde dice que nums es una matriz de tipo int y la memoria se asigna en función del número de elementos pasados ​​durante la inicialización.