¿Que dudas te genero C cuando empezaste a utilizarlo?

Iniciado por astinx, 12 Marzo 2012, 17:34 PM

0 Miembros y 1 Visitante están viendo este tema.

astinx

Hola, estoy haciendo un recopilatorio de dudas respecto a C. Sin embargo, cuando me pongo a pensar en que contenidos me dieron problemas cuando comencé con C, mucho no se me viene a la mente. Si, obviamente, todos hemos tenido nuestras dudas acerca de punteros, pero busco encontrar preguntas mas "finas", mas "particulares".
Estuve leyendo hasta la pagina 21 de este foro para buscar entre las dudas de los usuarios. Pero como siempre, y como a la mayoría nos ha sucedido, el principal objeto de duda suele ser, punteros a funciones, punteros, matrices, estructuras genéricas con punteros a void.

Las preguntas mas finas que se me vienen a la mente, por ejemplo, son:

¿Qué utilidad tiene un void*?, ¿Para que voy a querer castear como un puntero, (como por ejemplo, int*) si igualmente luego puede accederlo y tratarlo como se me antoje?, ¿Cual es el tamaño de un void?¿Por que viene dado?, ¿Por que usar Macros y no funciones o viceversa?

Pero como siempre, en todo el ámbito informático, uno nunca va a ver lo que otro puede, así que tal vez, ustedes en sus inicios con C tuvieron también, problemas particulares de la misma naturaleza.

Ya que estoy voy a poner dos pequeñas dudas que me acaban de surgir en este momento:
Java implementa los Comparadores utilizando punteros a funciones, ¿no?. Nunca investigue acerca del tema, pero recuerdo que cuando estaba estudiando punteros a funciones, fue así como dije:-"Ah esa es la utilidad de punteros a funciones".

¿Como implementarían ustedes un pequeño garbage collector en C?, la manera es sencilla, pero ¿como determinarían si una variable no ha sido usada durante mucho tiempo?, ¿Con una syscall y guardarían las posiciones de memoria de inicio de cada variable en un vector junto con la información relativa a cuando se ha usado?

Saludos y muchas gracias por detenerse a leer.
La programación hoy en día es una carrera entre los ingenieros de software intentando construir mejores y más eficientes programas a prueba de idiotas y el Universo intentando producir mejores y más grandes idiotas. De momento, el Universo está ganando

petrusqui

Yo hace poco que he empezado con C++ y las primeras preguntas que me vinieron fueron:

**¿Y ahora como puedo crear una interfaz grafica en windows?
**¿Diferencias entre debug i realease?
¿Se puede mezclar diferentes lenguajes en un mismo programa?
¿El mismo código sirve para todos los SO?


Las preguntas con "**" las tengo resuetas y las otras dos más o menos. Ests son las preguntas que tengo ahora, ya que soy bastante novato en esto de C/C++

Anastacio

Bueno, aqui siempre dicen (nunca uses void,), pero no te explican porque, o te explican a niveles que vos quedas  :huh: :huh: :huh: :o, y decis, a bueno, ya lo entendere.

El tema de void, por lo que se, void no devuelve nigun valor. No se si solo se usa para el main, o para otra cosa, yo nunca he visto ningun programa que tenga un void en algun lado (yo estudio viendo ejemplos y probando cosas con el compilador, jaja).

Las otras no las se, soy bastante novato.

Yo tengo treinta y tres mil dudas, y hace poco comenze (4 meses mas o menos), a estudiar C. Para que tengas una idea, hace unos pocos dias entendi finalmente como se usaba el operador %.
Saludos y suerte!!!!!!!!!!!!!
You, stop to close my post, you were novice too!!!!!!!!!!!!

Caballo_Alado

#3
Estas eran mis dudas antes de aprender sobre este lenguaje.

-¿sera C mejor que los demás?
-¿C++ o C?
-yo venía de saber algo de python a empezar a leer sobre C y la primera impresión que me dio fue que era complicadicimo, pero a medida uno se acostumbra un montón.
-Teniendo conocimientos sobre C, ¿podre hacer cualquier cosa que se me imagine en la pc?

salu2  ;)
♫           ♪ "I'm sexy and I know it"     ♪      ♫

Tic_Tak

Cuando empece a usarlo me preguntaba

¿En el futuro cuando trabaje lo usare?
R= Si es con lo que programa día a día en un ERP

¿Cuando usar void?

¿Que función tienen los punteros en un programa o cuando es viable usarlos?


astinx

Muy buenas preguntas. Gracias por ayudarme! ;)

Anastacio, para vos que tenías algunas dudas aca te dejo una info sobre punteros a funciones, la podes leer cuando quieras, lo mejor cuando uno arranca C, its do like a sloth, slowy is better! jajajaj osea no te precipites. Espero que te sea de ayuda.

Para los que tienen dudas acerca de los void, el void no solo sirve para decir que una función no devuelve nada, el void sirve para manipular direcciones de memoria directamente. Imaginense lo siguiente, cuando yo declaro una variable de algún tipo, tengo una posición de memoria reservada e identificada como de ese tipo. Si yo declaro un puntero a void (void*) tengo una dirección apuntada por el puntero, en esta dirección puedo tener cualquier dirección de cualquier otro dato, ¿Para que voy a querer tener en una variable las direcciones de memoria de otros datos? Bueno porque la principal propiedad del puntero a void es que se puede castear a cualquier otro tipo de puntero, de cualquier otro tipo de dato a excepción de algunas cosas que voy a detallar en este ejemplo:

#include <stdio.h>
#include <stdlib.h>
//Pequeña macro que nos dice la direccion de memoria de una variable
#define Address(x) printf("Address: %p\n",(&x)); fflush(stdout);

typedef void* Direccion;

int main(int argc, char** argv)
{
int a = 4;
//Esta es la unica manera de almacenar un valor en un puntero a void.
//Los punteros a void almacenan cualquier tipo de puntero.
Direccion dir=&a;
//No se puede asignar la direccion de una constante!
//ie Direccion dir=&b; Siendo b int const b = 45;
printf("-----------------\n");
Address(dir)
Address(dir)
printf("-----------------\n");
printf("a=%i\n",a);

//Vamos a modificar indirectamente el valor de la variable a
*(int *) dir = 65;
//Nota: Los punteros a miembros y los punteros a funciones no pueden asignarse a un puntero a void!
printf("-----------------\n");
Address(dir)
Address(dir)
printf("-----------------\n");
printf("a=%i\n",a);

printf("Siguen iguales! No podemos cambiar las referencias de un puntero, pero si copiar su contenido!\n");
printf("Tambien teniendo el puntero a void podemos castearlo para usar el valor al que apunta en diferentes formatos!\n");

printf("Imprimimos la variable a en char %c",(* ((char*) dir)));
return 0;
}


¿Y si tengo estructuras?, En ese caso se tiene que hacer que todos los elementos tengan el mismo tamaño que la estructura mas grande, sino al imprimirla o tratar con ella, supongase que tengo una estructura que pesa 12 bytes y tengo elementos de tipo int en la misma lista. Al imprimir todos los elementos, cuando quiera imprimir como del tipo de la estructura a los tipo int, va a tirar un segmentation fault. O sino tambien se puede tener una estructura "tipo nodo" que tenga un campo que permita discernir de que tipo es el elemento al que apunta.

#include <stdio.h>
#include <stdlib.h>
typedef struct asd{
char * n;
} asd;

int main() {
asd j;
int* k = (int*) malloc (sizeof(asd));
*k = 4;
j.n = "Hola\0";
void* dir=&j;
printf("%s\n",((asd*)(dir))->n);
printf("%i\n",(*((int*)(dir)))); 
dir = &k;
printf("%s\n",((asd*)(dir))->n);
printf("%i\n",(*((int*)(dir)))); 
return 0;
}




Muy bien, re lindo poder castear dinámicamente cualquier otra variable, pero ¿Para que me sirve realmente?, para armar estructuras genéricas, donde puedas tener varios tipos de datos. aqui tienen un ejemplo de una lista genérica:

#include <stdio.h>
#include <stdlib.h>

typedef struct t_Persona {
char* nombre;
char* apellido;
} t_Persona;

//Decimos que un puntero a void es sinonimo de una direccion.
typedef void* t_Direccion;

typedef struct t_Lista {
t_Direccion* dato;
//El size NO lo necesitamos simplemente para saber cuantos elementos tenemos, SI lo necesitamos para seguirle la pista
//A cuanto espacio tenemos que alocar.
int size;
} t_Lista;

//El tipo iterador contiene la lista y la posicion actual dentro de ella
typedef struct t_Iterador {
t_Lista* lista;
//Nodo actual para recorrer
int actual;
} t_Iterador;

t_Iterador tIterador_Crear () {
t_Iterador nue;
nue.lista= (t_Lista*) malloc (sizeof(t_Lista));
(nue.lista)->size=0;
(nue.lista)->dato=NULL;
nue.actual=0;
return nue;
}

void tIterador_Iniciar(t_Iterador* iter) {
iter->actual=0;
}

/* Notese la diferencia entre el crear y el iniciar; El crear nos crea una nueva instancia, y el iniciar
* prepara el iterador para iterar, recibiendo la lista sobre la cual va a trabajar y poniendo su posicion
* actual a cero. */

/*Un simple agregar al final*/

void tIterador_Agregar (t_Iterador* iter, t_Direccion i) {
if (iter->lista->size == 0) {
iter->lista->dato = (t_Direccion*) malloc (sizeof(t_Direccion)*(++iter->lista->size));
} else {
iter->lista->dato = (t_Direccion*) realloc (iter->lista->dato, sizeof(t_Direccion)*(++iter->lista->size));
}
iter->lista->dato[iter->actual++] = i;
}

/*Funciones que imprimen en diferentes formatos, utilizadas para el imprimir*/

void imprimirEnteros (t_Direccion x) {
printf("%i, ",*((int*)(x)));
}

void imprimirCaracteres (t_Direccion x) {
printf("%c, ",*((char*)(x)));
}

void imprimirStrings (t_Direccion x) {
printf("%s, ",((char*)(x)));
}

/* No escatimes en el uso del parentesis en estos casos!!! */
/* void imprimirPersonas (t_Direccion x) {
printf("%s %s, ",((t_Persona*)(x))->nombre, ((t_Persona*)(x))->apellido);
} */
/* En estos casos hay que asegurarse de que todos los elementos tienen el mismo tamaño*/

/*El imprimir generico*/
/*Nomenclatura de una funcion pasada como parametro a otra (puntero a funcion)
*TIPORETORNO (*NOMBRE)(PARAMETROS) Notese que para un puntero a funcion el asterisco se usa a la izquierda*/
void tIterador_Imprimir (t_Iterador* iter, void (*criterio)(t_Direccion)) {
criterio(iter->lista->dato[iter->actual]); /*Modo de uso de un puntero a funcion*/
}

int tIterador_Fin (t_Iterador* iter) {
return (iter->actual < iter->lista->size)?(1):(0);
}

void tIterador_Avanzar (t_Iterador* iter) {
iter->actual++;
}

int main(int argc, char** argv)
{

int a=65, b=66, c='a', d=68, e='c';
char* f = "Holaaa";
t_Iterador iter = tIterador_Crear();

tIterador_Iniciar(&iter);

/*Vamos a agregar los numeros del 65 al 70*/
tIterador_Agregar(&iter, &a);
tIterador_Agregar(&iter, &b);
tIterador_Agregar(&iter, &c);
tIterador_Agregar(&iter, &d);
tIterador_Agregar(&iter, &e);
tIterador_Agregar(&iter, f); //Look!

/*Imprimimos como enteros*/
tIterador_Iniciar(&iter);
/*Al imprimir le pasamos la funcion que va a usar como criterio de conversion*/
while ((tIterador_Fin(&iter))) {
tIterador_Imprimir(&iter, imprimirEnteros);
tIterador_Avanzar(&iter);
}
printf("\n");
/*Imprimimos como Caracteres*/
tIterador_Iniciar(&iter);
/*Al imprimir le pasamos la funcion que va a usar como criterio de conversion*/
while ((tIterador_Fin(&iter))) {
tIterador_Imprimir(&iter, imprimirCaracteres);
tIterador_Avanzar(&iter);
}
printf("\n");
/*Imprimimos como Strings*/
tIterador_Iniciar(&iter);
/*Al imprimir le pasamos la funcion que va a usar como criterio de conversion*/
while ((tIterador_Fin(&iter))) {
tIterador_Imprimir(&iter, imprimirStrings);
tIterador_Avanzar(&iter);
}

return 0;
}


Lo de t_Persona solamente lo deje expresado para que se sepa como se debería hacer la comparacion si se hubiera alocado el espacio suficiente.
La programación hoy en día es una carrera entre los ingenieros de software intentando construir mejores y más eficientes programas a prueba de idiotas y el Universo intentando producir mejores y más grandes idiotas. De momento, el Universo está ganando

theluigy13etv

-  ¿Cuál es la diferencia entre archivos de cabeceras, librerías, bibliotecas de función estándar?

-  ¿Por qué el Lenguaje C no tiene incorporado la entrada y salida?

- ¿Cuál es la diferencia entre Lenguaje C y compilador de C?

- ¿En qué lenguaje de programación escriben los compiladores?

(Algunas otras preguntas tontas que me hacía en un inicio)
- ¿Si Windows se escribió en Lenguaje C, entonces en qué lenguaje se escribió C, y en que lenguaje se escribio el lenguaje que permitió escribir C y así sucesivamente...?

- ¿Si los programas son creados a partir de otros programas, cuál es el programa matriz que dio origen a otros