elhacker.net cabecera Bienvenido(a), Visitante. Por favor Ingresar o Registrarse
¿Perdiste tu email de activación?.

 

 


Tema destacado: AIO elhacker.NET 2021 Compilación herramientas análisis y desinfección malware


  Mostrar Mensajes
Páginas: 1 2 3 4 5 6 7 8 9 10 [11] 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 ... 161
101  Programación / Programación C/C++ / Re: Error de printeo con puntero triple en: 22 Agosto 2021, 13:05 pm
No tiene sentido usar puntero triple. Lo que te importa es la dirección de memoria que contendrá pArreglo y cambiarlo en otra función. Como sabes un argumento de una función es una copia de un dato y para modificar el valor de una variable se pasa el puntero a esa variable (así el puntero es la copia y lo que hay dentro se modifica), por eso se pasa un puntero a puntero.

Como crearArreglo va a crear un array dinámico que debe ser devuelto (a a introducir en pArreglo un valor), esta función debe recibir la dirección de pArreglo (que es copia, pero su dato sí se puede modificar).

Ídem para asignarMemoria. No debe ser un puntero triple porque es realmente la encargada de crear el array e introducir esa dirección de memoria en pArreglo. La dirección de pArreglo ya la has pasado en el argumento punteroApuntero de crearArreglo y es lo que te interesa, así que se lo das sin más.

Totalmente diferente es el trabajo en copiarValores. Allí sólo te interesa rellenar el array, no debes modificar su dirección de memoria y por tanto debes pasarle la dirección del propio array. Vas a modificar su contenido.

Sería algo así:
Código
  1. #include <stdio.h>
  2. #include <stdlib.h>
  3. #include <time.h>
  4.  
  5. void crearArreglo(int **punteroApuntero, int dim);
  6. void asignarMemoria(int **punteroApuntero, int dim );
  7. void copiarValores(int *puntero, int dim);
  8.  
  9. int main()
  10. {
  11.    int *pArreglo = NULL;
  12.    int dim = 0; //dimension
  13.  
  14.    printf("\nIngrese la dimension del arreglo: ");
  15.    scanf("%d",&dim);
  16.  
  17.    srand(time(NULL)); //para obtener valores random en copiarValores()
  18.    crearArreglo(&pArreglo,dim); //se le pasa el puntero a puntero y la dimension
  19.  
  20.    printf("\nPrimer elemento desde main: %d\n",*pArreglo);
  21.  
  22.    free(pArreglo); // recuerda que siempre que adquieres memorias a mano debes liberarla a mano.
  23.  
  24.    return 0;
  25.  
  26. }// fin main
  27.  
  28. void crearArreglo(int **punteroApuntero, int dim)
  29. {
  30.    asignarMemoria(punteroApuntero, dim);
  31.  
  32.    copiarValores(*punteroApuntero, dim);
  33.  
  34. }// fin funcion crearArreglo
  35.  
  36. void asignarMemoria(int **punteroApuntero, int dim)
  37. {
  38.    (*punteroApuntero) = (int *) malloc ( dim * sizeof(int) );
  39.  
  40.    if( (*punteroApuntero) == NULL )
  41.    {
  42.        printf("\nError en asignacion de memoria.\n");
  43.        exit(EXIT_FAILURE);
  44.    }//fin if
  45.    else
  46.    {
  47.        printf("\nAsignacion de memoria exitosa.\n");
  48.  
  49.    } // fin else
  50.  
  51. } // fin funcion asignarMemoria
  52.  
  53. void copiarValores(int *puntero, int dim)
  54. {
  55.    for(int i=0; i<dim; ++i)
  56.    {
  57.        puntero[i] = rand() % 10;
  58.        printf("Elemento %d : %d\n",i,puntero[i]);
  59.        system("pause");
  60.    }// te lo cambio por un for. Es más conciso en este caso
  61.  
  62. } // fin funcion copiarValores
102  Programación / Programación C/C++ / Re: Separar los dígitos impares de un numero con guion en: 20 Agosto 2021, 20:41 pm
No entiendo la salida. ¿Qué hace que 2-3, 5-6, 6-7 sean validos pero no 1-2, 3-4, 4-5, 8-9?
103  Programación / Programación C/C++ / Re: Puntero doble en: 16 Agosto 2021, 10:45 am
Mejor sería reestructurar los tipos de datos: uno para tener guardar el dato mismo y otro para guardar la cola.

Verás que no se han hecho uso de punteros dobles. Muchas veces se pueden evitar

Dato:
Código
  1. typedef struct tDATO {
  2. int DNI;
  3. char * nombre;
  4. struct tDATO *siguiente;
  5. } *DATO;

El dato guarda la información útil más un puntero que hace la lista. En verdad se podría realizar una estructura anidada, la estructura interna con el dato y la externa que contendrá el puntero (pero eso ya más avanzado).

Cola:
Código
  1. typedef struct tCola {
  2.    DATO primero;
  3.    DATO ultimo;
  4.    size_t n_elementos;
  5. } *COLA;

La cola nos sirve para trabajar con la estructura cola, nada más. Guarda el primer dato, el último y el número de elementos.

Teniendo ya los dos tipos de datos estructurados vamos a crear la funcionalidad para manejarlos de forma sencilla. A por las funciones:

Para los datos .......

Primero vamos crear el dato

Código
  1. DATO dato_crear(int dni, char *nombre) {
  2.    DATO dato = malloc(sizeof(struct tDATO));
  3.    dato->DNI = dni;
  4.    dato->nombre = malloc((strlen(nombre)+1) * sizeof(char));
  5.    strcpy(dato->nombre, nombre);
  6.    dato->siguiente = NULL;
  7.  
  8.    return dato;
  9. }

Esto genera un tipo dato en memoria dinámica, nada del otro mundo. Lo único que hay que tener en cuenta es que los campos que se deben alojar en memoria dinámica, como nombre, debe hacerse mediante el uso de *alloc. Esto es especialmente así sobre todo en cadenas que te pueden venir de diferentes formas y no se puede asignar directamente el valor de la variable nombre a dato->nombre por la razón de que te pueden pasar un puntero de un array local y al salir de la función esa memoria sería liberada, es decir, si te hacen esto:

Código:
DATO dato_crear(int dni, char *nombre) {
    ...
    dato->nombre = nombre;
    ...
}

void generar_dato() {
    ...
    char nombre[] = "Tirant Lo Blanc";
    dato_crear(dni, nombre);
    ...
}

Repito, lo anterior está mal. Por otra parte se ve que 'siguiente' va a NULL, esto es así para que se puedan encontrar fallos de lógica.

Liberar dato de la memoria

Código
  1. void dato_liberar(DATO dato) {
  2.    free(dato->nombre);
  3.    free(dato);
  4. }

Antes de liberar el dato propiamente dicho hay que liberar la memoria que ha adquirido para su funcionamiento, en este caso la cadena nombre.

Como puedes haber observado este es el funcionamiento básico, no hay guardas para saber si no se han pasado datos NULL o que no hayan ocurrido errores, pero esto es a lo que vamos.

Vamos a por la cola.....

Primero se crea la cola

Código
  1. COLA cola_crear() {
  2.    COLA cola = malloc(sizeof(struct tCola));
  3.    cola->primero = NULL;
  4.    cola->ultimo = NULL;
  5.    cola->n_elementos = 0;
  6.  
  7.    return cola;
  8. }

Sencillo se genera en memoria dinámica y se ponen todos los elementos a 0 o NULL.

Agregar un dato a la cola

Código
  1. void cola_agregar(COLA cola, DATO dato) {
  2.    if(cola_es_vacia(cola)) {
  3.        cola->primero = dato;
  4.    } else {
  5.        cola->ultimo->siguiente = dato;
  6.    }
  7.    cola->ultimo = dato;
  8.    cola->n_elementos++;
  9. }

Los datos a una cola se introducen por el final, nuestro dato COLA ya tiene un puntero a su último elemento así que el trabajo es sencillo. Lo único que hay que tener en cuenta es si la cola está vacía: si está vacía el elemento introducido no sólo es el último sino que también es el primero; si la cola no está vacía hay que tener presente para el buen funcionamiento de nuestra estructura de datos que el último elemento de la cola apunte al que vamos a agregar.

Extraer un dato de la cola

Código
  1. DATO cola_extraer(COLA cola) {
  2.    DATO dato = cola->primero;
  3.  
  4.    if(!cola_es_vacia(cola)) {
  5.        cola->primero = cola->primero->siguiente;
  6.        dato->siguiente = NULL;
  7.        if(cola->primero == NULL) {
  8.            cola->ultimo = NULL;
  9.        }
  10.        cola->n_elementos--;
  11.    }
  12.  
  13.    return dato;
  14. }

Como en una pila los datos se extraen desde e principio. Es importante saber dos cosas: si al principio la cola está vacía por lo que se tendrá que devolver NULL y no hacer nada más; que después de la extracción la cola se vacíe (donde cola->primero tendrá el valor NULL) en ese caso y para evitar problemas lógicos también se lleva a NULL cola->ultimo.

Desalojar la cola de memoria

Código
  1. void cola_liberar(COLA cola) {
  2.    DATO x;
  3.    while(cola->primero) {
  4.        x = cola->primero;
  5.        cola->primero = cola->primero->siguiente;
  6.        dato_liberar(x);
  7.    }
  8.    free(cola);
  9. }

Como con dato primero hay que liberar toda la memoria que haya alojado. Esto se hace recorriendo la lista con cola->primero hasta que sea NULL. Ver que se usa la funcion dato_liberar porque cada dato se debe desalojar usando su propia función (ya que también hace su propia limpieza). Se podrían haber extraído datos con cola_extraer, pero sería más lento.

Después, para evitar trabajar directamente con el dato cola se pueden hacer algunas funciones auxiliares que de hecho ya se han usado en el código anterior, pero esas van más para un usuario de nuestro código:

Código
  1. int cola_es_vacia(COLA cola) {
  2.    return cola->n_elementos == 0;
  3. }
  4.  
  5. size_t cola_longitud(COLA cola) {
  6.    return cola->n_elementos;
  7. }
  8.  
  9.  
104  Programación / Programación C/C++ / Re: C ++ : Duda con Salto de línea entre cout y cin en: 15 Agosto 2021, 16:15 pm
Claro, dibuja tu mismo ese salto de línea:
Escribes "Cuál es tu nombre?\n"
-- El usuario introduce su nombre --
Escribes "\nTe llamas [nombre]"

Nota el carácter de salto de línea '\n'.
105  Programación / Programación C/C++ / Re: Puntero doble en: 15 Agosto 2021, 16:06 pm
Bueno, la verdad es que es te estás liando un poco con los punteros y los dobles punteros.

Código:
(*aux)->sgte = nuevoNodo;

Aquí nuevoNodo es COLA * nuevoNodo, lo que es lo mismo, struct tCola ** nuevoNodo (un puntero doble). Pero sgte espera un puntero simple:

Código:
typedef struct tCola {
DATO contenido;
struct tCola *sgte;
} * COLA;

En la definición se puede ver que sgte es un puntero simple.

Ídem para
Código:
aux = (*aux)->sgte;
106  Programación / Programación C/C++ / Re: Salto de un personaje en c++ en: 14 Agosto 2021, 15:10 pm
El sistema guarda las pulsaciones del teclado en un buffer. kbhit, getch, getchar, scanf, etc. lo que hacen es leer desde ese búffer. Esto es porque es muy improbable que un usuario pulse una tecla en el momento preciso que tu la pides.

Por tanto debes encontrar una forma de descartar esas pulsaciones mientras estés en el aire (por ejemplo que cuando toques el suelo primero se vacíe el búffer del teclado (una única vez) y a partir de después ver si pulsa la tecla de salto.

Otra idea sería que mientras estás en el aire puedas recibir las pulsaciones de teclado del usuario pero no hacer nada ante ellas.
107  Programación / Programación C/C++ / Re: No lee instrucciones de main en: 12 Agosto 2021, 02:00 am
Me he tomado la libertad de modificar tu código y añadir unas cuantas cosas. De igual forma he comentado cambios y añadidos.

Espero que te sirva.

Código
  1. #include <stdio.h>
  2. #include <stdlib.h>
  3.  
  4. typedef struct rNodo {
  5.    int dato;
  6.    struct rNodo * siguiente;
  7. } tNodo;
  8.  
  9. typedef struct rLista {
  10.    tNodo * primero;
  11.    tNodo * ultimo;
  12.    int longitud;
  13. } tLista;
  14.  
  15. typedef tNodo * Nodo;
  16. typedef tLista * Lista;
  17.  
  18. tLista* inicializar();
  19. tNodo* crear_nodo(int nuevo_dato);
  20. void ins_de_orden_ascen(Lista lista, Nodo nuevo_nodo);
  21. void mostrar(Lista lista);
  22. void liberar(Lista lista);
  23.  
  24. int main(void) {
  25.    Lista lista = inicializar();
  26.    int nuevo_dato;
  27.    int continuar; // cambio el nombre de variable para hacerlo  más coherente. No lo inicializo ya que en el bucle se debe hacer obligatoriamente.
  28. do {
  29. printf("ingrese un numero: ");
  30.        scanf("%i", &nuevo_dato);
  31.        ins_de_orden_ascen(lista, crear_nodo(nuevo_dato));
  32.        printf("Quiere ingresar otro numero? 1(si) o 0(no): ");
  33.        scanf("%i", &continuar);
  34.    } while (continuar);
  35.  
  36.    mostrar(lista);
  37.    liberar(lista);
  38.    return 0;
  39. }
  40.  
  41.  
  42. tLista* inicializar() { // no tiene razón la existencia de un argumento, no se usaba
  43.    Lista nueva_lista = malloc(sizeof (tLista));
  44.    nueva_lista->primero = NULL;
  45.    nueva_lista->ultimo = NULL;
  46.    nueva_lista->longitud = 0;
  47.    return nueva_lista;
  48. }
  49.  
  50. tNodo* crear_nodo(int nuevo_dato) {
  51.    Nodo nuevo_elemento = malloc(sizeof (tNodo));
  52.    nuevo_elemento->dato = nuevo_dato;
  53.    nuevo_elemento->siguiente = NULL;
  54.    return nuevo_elemento;
  55. }
  56.  
  57. void ins_de_orden_ascen(Lista lista, Nodo nuevo_nodo) { // no tiene razón que se devuelva la lista, no se modifica su puntero
  58.    if (lista->longitud == 0) { // Si la lista es vacia
  59.        nuevo_nodo->siguiente = lista->primero;
  60.        lista->primero = nuevo_nodo;
  61.        lista->ultimo = nuevo_nodo;
  62.    } else {
  63.        Nodo aux = lista->primero; // aux apunta al primer elemento
  64.        Nodo ant = NULL;
  65.        while(aux && aux->dato < nuevo_nodo->dato) { // busco el nodo con un dato mayor al nuevo dato, también puede llegar al fin de la lista
  66.            ant = aux; // y me quedo con el nodo anterior
  67.            aux = aux->siguiente;
  68.        }
  69.        if(ant) { // si el nodo anterior existe
  70.            ant->siguiente = nuevo_nodo; // hago que su siguiente apunte al nuevo nodo
  71.            if(lista->ultimo == ant) { // si el nodo anterior era el último de la lista
  72.                lista->ultimo = nuevo_nodo; // ahora debe serlo el nuevo nodo
  73.            }
  74.        } else {
  75.            lista->primero = nuevo_nodo; // en caso contrario quiere decir que el nuevo nodo debe ser el primero
  76.        }
  77.        nuevo_nodo->siguiente = aux; // el siguiente del nodo nuevo debe ser el nodo que debía ser el siguiente, o NULL si había llegado al final de la lista
  78.  
  79.    }
  80.    lista->longitud++; // Aumenta la cantidad de elementos
  81. }
  82.  
  83. void mostrar(Lista lista) { // pinta la lista en pantalla
  84.    puts("--- Lista ---");
  85.    if(!lista) { // No existe lista
  86.        printf("Lista no inicializada");
  87.        return;
  88.    }
  89.    if(lista->longitud == 0) { // Lista vacía
  90.        printf("Lista vacía");
  91.        return;
  92.    }
  93.  
  94.    for(Nodo n = lista->primero; n; n = n->siguiente) { // Muestra todos los nodos
  95.        printf("%d\n", n->dato);
  96.    }
  97. }
  98.  
  99. void liberar(Lista lista) { // Desaloja la lista de la memoria
  100.    Nodo sig;
  101.    if(!lista) { // Si no existe lista no hay que liberar nada
  102.        return;
  103.    }
  104.    while(lista->primero) {
  105.        sig = lista->primero->siguiente;
  106.        free(lista->primero);
  107.        lista->primero = sig;
  108.        // lista->longitud--; // No hace falta esta línea ya que la lista se va a desalojar de la memoria
  109.    }
  110.    free(lista);
  111. }
108  Programación / Programación C/C++ / Re: la biblioteca string.h o string, esta bien usarlo? en: 5 Agosto 2021, 10:53 am
De string no sé, eso es de C++, pero si te puedo decir de C. Sí string.h tiene funciones que no son seguras y por ello se hicieron unas parecidas pero que el programador le decía a la función cuántos bytes tenías que usarse: por ejemplo strcpy y strncpy, strcat y strncat, etc.

También hay funcionalidad para manejar caracteres anchos.

Te recomiendo que descargues el proposal para C17 (la normal del estándar hay que pagarla) y veas qué puede hacer C https://web.archive.org/web/20181230041359if_/http://www.open-std.org/jtc1/sc22/wg14/www/abq/c17_updated_proposed_fdis.pdf
109  Programación / Programación C/C++ / Re: Invocacion funcion con variables de tipo puntero en: 20 Julio 2021, 17:15 pm
Tienes un problema en la línea 3:
Para crear los diferentes elementos del array has escrito
Código:
(1,1,0,1,1),(1,1,1,1,1),(1,0,1,1,1),(1,1,1,1,1),(0,1,1,1,1)

Con los paréntesis no generas elementos, sino que agrupas operaciones. Pues bien dentro de los paréntesis estás usando el operador coma.

El operador coma es un operador binario que evalúa la primera expresión y descarta su valor, después evalúa la segunda expresión y devuelve el resultado. Encadenando expresiones, cómo lo has hecho estás devolviendo el último operando de cada grupo de paréntesis.

Por otra parte, cuándo inicializas un array se puede hacer de forma incompleta dando valor a las primeras posiciones; el compilador entiende que debe dejar las siguientes a 0 por lo que en realidad tu código genera el siguiente array:
Código:
1 1 1 1 1
0 0 0 0 0
0 0 0 0 0
0 0 0 0 0
0 0 0 0 0

Para solucionar esto sólo cambia los paréntesis por llaves en tu inicialización del array.
110  Programación / Programación C/C++ / Re: Leer un string con memoria dinámica ? en: 19 Julio 2021, 00:41 am
No la liberas a mano. De esa se encarga C. Por eso si intentas liberar con free te saltará el error. Y no, la memoria puedes hacer una cadena tan larga como quieras. En los sistemas modernos el propio sistema no te dejará porque impide que los programas escriban o lean en direcciones de memoria que no están autorizados. En sistemas sin protección podrías escribir una cadena tan larga que podría sobreescribir cualquier parte de la memoria, y eso eran los ataques de buffer overflow.
Páginas: 1 2 3 4 5 6 7 8 9 10 [11] 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 ... 161
WAP2 - Aviso Legal - Powered by SMF 1.1.21 | SMF © 2006-2008, Simple Machines