memoria - punteros en c
Concepto de puntero de vacío en la programación de C (14)
Quiero hacer que esta función sea genérica, sin usar ifs; ¿Es posible?
La única manera simple que veo es utilizar sobrecarga ... que no está disponible en C programación langage AFAIK.
¿Consideró el lenguaje de programación C ++ para su programa? ¿O hay alguna restricción que prohíba su uso?
¿Es posible desreferenciar un puntero vacío sin conversión de texto en el lenguaje de programación C?
Además, ¿hay alguna forma de generalizar una función que puede recibir un puntero y almacenarlo en un puntero de vacío y al usar ese puntero vacío, podemos hacer una función generalizada?
por ejemplo:
void abc(void *a, int b)
{
if(b==1)
printf("%d",*(int*)a); // If integer pointer is received
else if(b==2)
printf("%c",*(char*)a); // If character pointer is received
else if(b==3)
printf("%f",*(float*)a); // If float pointer is received
}
Quiero hacer que esta función sea genérica sin usar sentencias if-else, ¿es esto posible?
Además, si hay buenos artículos de Internet que explican el concepto de un puntero nulo, sería beneficioso proporcionar las URL.
Además, ¿es posible la aritmética de punteros con punteros vacíos?
¿Es posible desreferenciar el puntero vacío sin conversión de texto en el lenguaje de programación C ...?
No, el void
indica la ausencia de tipo, no es algo que puede desreferenciar o asignar.
¿Hay alguna manera de generalizar una función que puede recibir puntero y almacenarlo en el puntero de vacío y mediante el uso de ese puntero vacío podemos hacer una función generalizada?
No puede desreferenciarlo de manera portátil, ya que puede no estar alineado correctamente. Puede ser un problema en algunas arquitecturas como ARM, donde el puntero a un tipo de datos debe alinearse en el límite del tamaño del tipo de datos (por ejemplo, el puntero al entero de 32 bits debe alinearse en el límite de 4 bytes para desreferenciarse).
Por ejemplo, leyendo uint16_t
desde void*
:
/* may receive wrong value if ptr is not 2-byte aligned */
uint16_t value = *(uint16_t*)ptr;
/* portable way of reading a little-endian value */
uint16_t value = *(uint8_t*)ptr
| ((*((uint8_t*)ptr+1))<<8);
Además, es posible la aritmética de punteros con punteros vacíos ...
La aritmética del puntero no es posible en los punteros del void
debido a la falta de valor concreto debajo del puntero y, por lo tanto, al tamaño.
void* p = ...
void *p2 = p + 1; /* what exactly is the size of void?? */
Como C es un lenguaje de tipo estático y fuertemente tipado, debe decidir el tipo de variable antes de la compilación. Cuando intente emular los genéricos en C, terminará intentando reescribir C ++ nuevamente, por lo que sería mejor usar C ++ en su lugar.
Debe tener en cuenta que en C, a diferencia de Java o C #, no hay absolutamente ninguna posibilidad de "adivinar" con éxito el tipo de objeto al que apunta un puntero void *. Algo similar a "getClass ()" simplemente no existe, ya que esta información no se encuentra por ningún lado. Por esa razón, el tipo de "genérico" que está buscando siempre viene con metainformación explícita, como la "int b" en su ejemplo o la cadena de formato en la familia de funciones printf.
En C, un void *
se puede convertir en un puntero a un objeto de un tipo diferente sin un molde explícito:
void abc(void *a, int b)
{
int *test = a;
/* ... */
Sin embargo, esto no ayuda a escribir su función de una manera más genérica.
No puede desreferenciar un void *
con la conversión a un tipo de puntero diferente, ya que la desreferenciación de un puntero obtiene el valor del objeto apuntado. Un void
descubierto no es un tipo válido, por lo que no es posible eliminar un void *
.
La aritmética del puntero consiste en cambiar los valores del puntero por múltiplos del sizeof
los objetos apuntados. Nuevamente, como void
no es un tipo verdadero, sizeof(void)
no tiene ningún significado así que la aritmética del puntero no es válida en void *
. (Algunas implementaciones lo permiten, usando la aritmética de puntero equivalente para char *
)
Esto no funcionará, sin embargo, void * puede ayudar mucho al definir un puntero genérico para las funciones y pasarlo como argumento a otra función (similar a la retrollamada en Java) o definir una estructura similar a oop.
Hasta ahora, mi comprensión del puntero void es la siguiente.
Cuando se declara una variable de puntero usando la palabra clave void, se convierte en una variable de puntero de propósito general. La dirección de cualquier variable de cualquier tipo de datos (char, int, float, etc.) se puede asignar a una variable de puntero void.
main()
{
int *p;
void *vp;
vp=p;
}
Como otro puntero de tipo de datos se puede asignar al puntero de vacío, lo usé en la función absolut_value (código que se muestra a continuación). Para hacer una función general.
Traté de escribir un código C simple que toma un número entero o flotante como un argumento y trata de hacerlo + ve, si es negativo. Escribí el siguiente código,
#include<stdio.h>
void absolute_value ( void *j) // works if used float, obviously it must work but thats not my interest here.
{
if ( *j < 0 )
*j = *j * (-1);
}
int main()
{
int i = 40;
float f = -40;
printf("print intiger i = %d /n",i);
printf("print float f = %f /n",f);
absolute_value(&i);
absolute_value(&f);
printf("print intiger i = %d /n",i);
printf("print float f = %f /n",f);
return 0;
}
Pero estaba obteniendo un error, así que llegué a saber mi comprensión con el puntero void no es correcto :(. Así que ahora voy a avanzar hacia la recopilación de puntos por qué es así.
Las cosas que necesito para entender más en punteros vacíos es eso.
Necesitamos encasillar la variable del puntero void para desreferenciarla. Esto se debe a que un puntero void no tiene ningún tipo de datos asociado. No hay forma de que el compilador pueda saber (¿o adivinar?) A qué tipo de datos apunta el puntero de vacío. Entonces, para tomar los datos apuntados por un puntero de vacío, lo encasillamos con el tipo correcto de datos dentro de la ubicación de los punteros vacíos.
void main()
{
int a=10;
float b=35.75;
void *ptr; // Declaring a void pointer
ptr=&a; // Assigning address of integer to void pointer.
printf("The value of integer variable is= %d",*( (int*) ptr) );// (int*)ptr - is used for type casting. Where as *((int*)ptr) dereferences the typecasted void pointer variable.
ptr=&b; // Assigning address of float to void pointer.
printf("The value of float variable is= %f",*( (float*) ptr) );
}
Un puntero de vacío puede ser realmente útil si el programador no está seguro sobre el tipo de datos de datos ingresados por el usuario final. En tal caso, el programador puede usar un puntero de vacío para señalar la ubicación del tipo de datos desconocido. El programa se puede configurar de tal manera que se le solicite al usuario que informe el tipo de datos y se puede realizar el moldeado de acuerdo con la información ingresada por el usuario. Un fragmento de código se proporciona a continuación.
void funct(void *a, int z)
{
if(z==1)
printf("%d",*(int*)a); // If user inputs 1, then he means the data is an integer and type casting is done accordingly.
else if(z==2)
printf("%c",*(char*)a); // Typecasting for character pointer.
else if(z==3)
printf("%f",*(float*)a); // Typecasting for float pointer
}
Otro punto importante que debe tener en cuenta acerca de los punteros vacíos es que la aritmética del puntero no puede realizarse en un puntero de vacío.
void *ptr;
int a;
ptr=&a;
ptr++; // This statement is invalid and will result in an error because ''ptr'' is a void pointer variable.
Entonces ahora entendí cuál fue mi error. Estoy corrigiendo lo mismo.
Referencias
http://www.antoarts.com/void-pointers-in-c/
http://www.circuitstoday.com/void-pointers-in-c .
El nuevo código es como se muestra a continuación.
#include<stdio.h>
#define INT 1
#define FLOAT 2
void absolute_value ( void *j, int *n)
{
if ( *n == INT) {
if ( *((int*)j) < 0 )
*((int*)j) = *((int*)j) * (-1);
}
if ( *n == FLOAT ) {
if ( *((float*)j) < 0 )
*((float*)j) = *((float*)j) * (-1);
}
}
int main()
{
int i = 0,n=0;
float f = 0;
printf("Press 1 to enter integer or 2 got float then enter the value to get absolute value/n");
scanf("%d",&n);
printf("/n");
if( n == 1) {
scanf("%d",&i);
printf("value entered before absolute function exec = %d /n",i);
absolute_value(&i,&n);
printf("value entered after absolute function exec = %d /n",i);
}
if( n == 2) {
scanf("%f",&f);
printf("value entered before absolute function exec = %f /n",f);
absolute_value(&f,&n);
printf("value entered after absolute function exec = %f /n",f);
}
else
printf("unknown entry try again/n");
return 0;
}
Gracias,
No, no es posible. ¿Qué tipo debe tener el valor desreferenciado?
Puede imprimir fácilmente una impresora vacía
int p=15;
void *q;
q=&p;
printf("%d",*((int*)q));
Un puntero de vacío en c se conoce como puntero genérico . El significado literal del puntero genérico es un puntero que puede señalar cualquier tipo de datos .
void *ptr;
No podemos desreferenciar el puntero genérico a ningún otro puntero.
Podemos encontrar el tamaño del puntero genérico utilizando el operador sizeof.
El puntero genérico puede contener cualquier tipo de punteros, como puntero, struct puntero, matriz de puntero, etc. sin ningún tipo de conversión.
Cualquier tipo de puntero puede contener un puntero genérico sin ningún tipo de conversión.
Los punteros genéricos se utilizan cuando queremos devolver ese puntero que se aplica a todos los tipos de punteros. Por ejemplo, el tipo de retorno de la función malloc es un puntero genérico porque puede asignar dinámicamente el espacio de memoria a las tiendas enteros, float, estructura, etc., por lo tanto, escribimos su tipo de devolución al tipo de puntero apropiado.
Un puntero void se conoce como puntero genérico, que puede referirse a variables de cualquier tipo de datos.
void pointer es un puntero genérico. La dirección de cualquier tipo de datos de cualquier variable se puede asignar a un puntero void.
int a = 10;
float b = 3.14;
void *ptr;
ptr = &a;
printf( "data is %d " , *((int *)ptr));
//(int *)ptr used for typecasting dereferencing as int
ptr = &b;
printf( "data is %f " , *((float *)ptr));
//(float *)ptr used for typecasting dereferencing as float
¿Cuál es el puntero de vacío en c?
Un puntero void en c se denomina puntero genérico, no tiene ningún tipo de datos asociado. Puede almacenar la dirección de cualquier tipo de objeto y se puede convertir a cualquier tipo. Según el estándar C, el pointer a void tendrá los mismos requisitos de representación y alineación que un puntero a un tipo de carácter. Una declaración de puntero void es similar al puntero normal, pero la diferencia es que en lugar de los tipos de datos utilizamos la palabra clave void .
Sintaxis:
void * Pointer_Name;
void *pvHandle;
Desreferenciando un puntero de vacío en C
Usando el operator indirección (*) podemos recuperar el valor apuntado por el puntero, pero en el caso del puntero void no podemos usar el operador de indirección directamente. Esto se debe a que un puntero void no tiene ningún tipo de datos que crea un problema para el compilador para predecir el tamaño del objeto puntiagudo. Entonces, antes de desreferenciar el vacío *, tenemos que escribir "cast it", habilita al compilador para predecir los tipos de datos.
Veamos un código de ejemplo.
#include <stdio.h>
#include <stdlib.h>
int main(int argc, char *argv[])
{
void *pvData;
int iData = 10;
pvData = &iData;
printf("*pvData = %d",*pvData);
return 0;
}
Explicación: Cuando compilamos el código anterior, obtendremos el error del compilador porque en el código anterior traté de eliminar la referencia del puntero void sin tipo de mayúsculas y minúsculas.
Pero lo que sucedió si escribimos el puntero void, está funcionando bien, mira el código de ejemplo a continuación.
#include <stdio.h>
#include <stdlib.h>
int main(int argc, char *argv[])
{
void *pvData;
int iData = 10;
pvData = &iData;
printf("iData = %d",*(int*)pvData);
return 0;
}
¿Por qué se usan punteros vacíos?
Una característica muy importante del puntero void es la reutilización. Usando el puntero void podemos almacenar la dirección de cualquier objeto y siempre que sea necesario podemos devolver el objeto a través del operador de direccionamiento indirecto con un casting adecuado.
De acuerdo con c la operación aritmética estándar en punteros vacíos es ilegal, lo que significa que el estándar C no permite la aritmética del puntero con punteros vacíos. Sin embargo, en GNU C, las operaciones de suma y resta son compatibles con punteros vacíos para suponer que el tamaño del vacío es 1.
Referencias
void abc(void *a, int b) {
char *format[] = {"%d", "%c", "%f"};
printf(format[b-1], a);
}