Menú

Mostrar Mensajes

Esta sección te permite ver todos los mensajes escritos por este usuario. Ten en cuenta que sólo puedes ver los mensajes escritos en zonas a las que tienes acceso en este momento.

Mostrar Mensajes Menú

Temas - MAFUS

#1
Programación C/C++ / Sobrecarga del operador +
25 Diciembre 2021, 20:58 PM
Buenas, chavales. Feliz Navidad y aniversario de Newton.

Estaba yo haciendo prácticas de C++ (le voy a dar una oportunidad) y no llego a entender del todo porqué saca unos resultados tan raros.

El código:
Código (cpp) [Seleccionar]
#include <iostream>

class vector {
private:
    int *n;
    int tamano;

public:
    vector(int tamano = 5);
    ~vector();
    void visualizar();
    void llenar();
    vector operator + (vector &);
    int& operator[] (int i) { return n[i]; };
};

vector::vector(int t):tamano(t) {
    n = new int[tamano];
    llenar();
}

vector::~vector() {
    delete[] n;
}

vector vector::operator + (vector &v) {
    vector resultado(tamano);
    for(int i=0; i<tamano; ++i) {
        resultado[i] = n[i] + v[i];
    }
    return resultado;
}

void vector::visualizar() {
    for(int i=0; i<tamano; ++i) {
        std::cout << n[i] << '\t';
    }
    std::cout << std::endl;
}

void vector::llenar() {
    for(int i=0; i<tamano; ++i) {
        n[i] = rand() % 10;
    }
}

int main() {
    vector a, b;
    a.visualizar();
    b.visualizar();
   
    vector c;
    c = a + b;
    c.visualizar();
   
    vector d = a + b;
    d.visualizar();

    return 0;
}


El resultado:
1       7       4       0       9
4       8       8       2       4
1577824 0       1573200 0       13
5       15      12      2       13


Es decir: porqué 'c' no y 'd' sí.
#2
Programación C/C++ / Divertimento: Hello world!
27 Agosto 2019, 19:04 PM
#include <stdio.h>

int main() {
   int w,t,f;
   w = 3;
   f = 1214606441+w;
   there:
   t=32;
   here:
   putchar(f>>(t-=8)&0377);
   if(t) goto here;
   f += w==3? 649792259 : 55307442;
   if(--w) goto there;
}
#3
El otro día, mientras aprendía Python, me fijé en foreach y range. Me pregunté si en C se podía tener una expresión parecida.

Y llegué a este ejemplo básico.


#include <stdio.h>

// Desde 1 hasta top. Haz lo que quiereas con el valor en medio ------------------------------
#define foreach(var, top) for(int foreach_var = (top); var = f(foreach_var); foreach_var = 0)

int f(unsigned number) {
    static unsigned top;
    static unsigned actual;

    if(number != 0) {
        top = number;
        actual = 0;
    }

    if(actual == top)
        return 0;

    return ++actual;
}
// -------------------------------------------------------------------------------------------

int main(){
    int x;
   
    /* Nueva funcionalidad */
    foreach(x, 5) {
        printf("%d\n", x);
    }
}


Lo dicho, es básico, pero se podría ir mejorando o hacer otras cosas, por supuesto.
#4
Hace unos días me encontré que existía la siguiente notación para definir un array:
#include <stdio.h>

int main() {
   char c[] = {[0 ... 26]'='};
   int d[] = {[0 ... 4]1, [8 ... 12]2};

   printf("\n%s\n", c);
   for(int i=0; i<sizeof(d)/sizeof(d[0]); ++i)
       printf(" %d", d[i]);
   printf("\n%s\n", c);
}
#5
Posiblemente las dos funciones más extrañas de C y con menor uso, según he visto. Por eso: a parte de simular excepciones ¿Qué uso se les podría dar a ese par de funciones? Por mi parte todavía no se me ha ocurrido ni presentado la ocasión de usarlas.
#6
Es frecuente en este foro encontrarse con gente que sigue trabajando con TurboC de Borland con la líbrería conio.h y normalmente la usan para dos o tres funciones: gotoxy, getch y getche. Para los que trabajamos con Linux nos da un poco de pereza ir editando todas esas líneas para hacer el código ejecutable. Pues bien, a raíz de eso he decidido hacerme una pequeña conio para quitarme de encima susodicho trabajo y ahora quiero compartirla con vosotros.

conio.h
#ifndef CONIO_PARA_LINUX
#define CONIO_PARA_LINUX

#include <stdio.h>
#include <termios.h>

void gotoxy(int x, int y) {
    printf("\33[%d;%df", y, x);
}

static char getch_interno(int eco) {
    char c;
    struct termios old, new;
   
    tcgetattr(0, &old);
    new = old;
    new.c_lflag &= ~ICANON;
    new.c_lflag &= eco ? ECHO : ~ECHO;
    tcsetattr(0, TCSANOW, &new);
    c = getchar();
    tcsetattr(0, TCSANOW, &old);
   
    return c;
}

char getch() {
    return getch_interno(0);
}

char getche() {
    return getch_interno(1);
}

#endif
#7
Intentando responder a un post y, como siempre pruebo el código de mi respuesta antes, necesitaba de una forma genérica una instrucción para limpiar el buffer de entrada stdin después de adquirir una cadena de entrada mediante fgets.

fgets, según el largo de la cadena introduce saca de stdin el carácter '\n' o no y si se usa while (getchar() != '\n'); sin que haya un carácter de nueva línea en el buffer el programa se detiene y espera a que el usuario introduzca algo. Y eso no queda bien.. Por otra parte controlar a mano si hay o no un carácter de nueva línea es engorroso y ensucia el código.

Llegué a la siguiente solución. Necesita de la librería string.h.


#include <string.h>

#define clrfstr(X) { \
   if(!strchr((X), '\n')) \
       while(getchar() != '\n'); \
}


Esto vacía, o no, stdin dependiendo de si ha la cadena ingresada contiene, o no, el carácter de nueva línea.

El código se debe incluir justo después de fgets o de la función que se haya usado para adquirir la cadena. X es el argumento que representa a la variable cadena adquirida.
#8
Como digo esto se trata de C y no de C++.

Es posible emular, en C, el comportamiento de miembros privados de datos definidos por el programador, al estilo de la POO, para que los usuarios de esa estructura no puedan acceder directamente a los datos que hay dentro de ella.

Las ventajas que tiene esta técnica:
1. El usuario no puede modificar los datos directamente y deben pasar por los filtros que imponga el programador.
2. El programador puede cambiar los datos internos que tiene la estructura y su interfaz (funciones getters y setters) sin que el usuario tenga que recompilar todo su código para hacer uso de estas modificaciones.

Los inconvenientes:
1. Sólo se puede situar la estructura en memoria del montón con lo que aparece el problema de la fragmentación de la memoria
2. La memoria se debe liberar ya sea mediante free o una función que proporcione el programador a modo de destructor.

Aquí va el código:


dato.h

#ifndef __DATO_H__
#define __DATO_H__

typedef struct __dato__ DATO;

DATO* new_dato();
void delete_dato(DATO* objeto);
int get_dato(DATO* objeto);
void set_dato(DATO* objeto, int valor);

#endif



dato.c

#include <stdlib.h>
#include "dato.h"

struct __dato__ {
   int miembro_privado;
};

DATO* new_dato() {
   DATO* d = malloc(sizeof(DATO));
   d->miembro_privado = 0;
   return d;
}

void delete_dato(DATO* objeto) {
   free(objeto);
}

int get_dato(DATO* objeto) {
   return objeto->miembro_privado;
}

void set_dato(DATO* objeto, int valor) {
   objeto->miembro_privado = valor;
}




Ahora el cliente:

main.c

#include <stdio.h>
#include "dato.h"

int main() {
   DATO *d;
   
   d = new_dato();
   set_dato(d, 5);
   printf("%i\n", get_dato(d));
   
   /* d->miembro_privado = 4; /* <- Esto va a fallar */
   /* printf("%i\n", get_dato(d)); */
   
   delete_dato(d);
   
   return 0;
}
#9
What the?

Pues sí, los chicos de Canonical han portado BASH de su Linux a Windows 10 y éste ejecuta el entorno de forma nativa, como si fuera el propio Linux.
Este BASH viene con todo lo que se podría esperar de él: awk, sed, grep, vi, etc. y junto al gestor de paquetes apt así que se pueden descargar paquetes como emacs.

¿Qué os parece este acercamiento?

http://www.hanselman.com/blog/DevelopersCanRunBashShellAndUsermodeUbuntuLinuxBinariesOnWindows10.aspx
#10
Ya va dos veces que intento realizar una respuesta en el foro de C/C++ y el sistema de protección me bloquea. ¿Cuáles son las nuevas reglas que espera el foro?
#11
Es cierto que GeSHi es poco descriptivo y, sobre todo para la gente nueva que entra, no se pondrá a jugar con cada una de las opciones de formato antes de postear su duda así que van a dejar el código en texto llano. Yo también lo he hecho.

Por eso en vez de tener el título GeSHi, la lista desplegable debería titularse 'elige tu lenguaje...' o 'Código en lenguaje...'; o algo que a primera vista ya diera a entender que eso sirve para que el código que va dentro se va a formatear en el lenguaje que se elija.
#12
Ya me había acostumbrado a que la ñ y las letras con tilde en los foros aparecen mal escritas cuándo se muestra código, pero mi sorpresa fue cuándo vi que en los mensajes privados sí se ven bien.
Por tanto esto es una sugerencia.
Por lo visto los mensajes privados y los foros están en codificaciones diferentes. Se podrían arreglar los foros para permitir tildes y la ñ.

Sí, pongo tildes en los comentarios  :rolleyes:
#13
Muy buenas.

Pues sigo con mi cruzada de autodescubrimiento de gramáticas extrañas que C acepta.

Supongamos la siguiente función que acepta un array de cadenas y las va imprimiendo hasta encontrar una cadena vacía:

void func(char* str[]) {
    int i = 0;
    while(str[i][0] != '\0')
        printf("%s\n", str[i++]);
}


Ante esto uno piensa que para llamar a dicha función debe crear una variable de esta forma
char *lista[] = {"uno", "dos", "tres", "cuatro", "");
y después llamar a la función
func(lista);

Pues se puede llamar a la función pasando un argumento anónimo, la lista entera directamente, de esta forma
func((char*[]){"uno", "dos", "tres", "cuatro", ""});

Obviamente, como siempre, esto se puede modificar al gusto y necesidades de cada uno.

Un programa de prueba completo es este:
#include <stdio.h>

void func(char* str[]) {
    int i = 0;
    while(str[i][0] != '\0')
    printf("%s\n", a[i++]);
}

int main()
{
    func((char*[]){"uno", "dos", "tres", "cuatro", ""});
    return 0;
}


Ya me diréis que os parece  ;)
#14
Muy buenas.

Pues la idea es hacer algo parecido a los delegados de C# pero con el C de toda la vida.
Sobre una lista dinámica de diferentes funciones con la misma firma se puede hacer las siguientes operaciones:
· Añadir funciones al final de la lista
· Quitar la primera aparición de una función dada
· Vaciar la lista de una tacada
· Ejecutar todas las funciones de la lista de forma secuencial y con unos parámetros comunes dados en la llamada a la ejecución.

En este programa se trabaja sobre una función que acepta un char* y no devuelve nada, pero se puede modificar fácilmente para trabajar con otras funciones.


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

typedef struct tdelegate {
void (*func)(char*);
struct tdelegate *next;
} DELEGATE;

int delegate_add(DELEGATE **pdelegate, void (*funcpointer)(char*)) {
DELEGATE *newdelegate = malloc(sizeof(DELEGATE));
DELEGATE *aux = NULL;

if(newdelegate == NULL)
return 0;

newdelegate->func = funcpointer;
newdelegate->next = NULL;

if(*pdelegate == NULL)
*pdelegate = newdelegate;
else {
aux = *pdelegate;
while(aux->next != NULL)
aux = aux->next;
aux->next = newdelegate;
}
return 1;
}

void delegate_exec(DELEGATE **pdelegate, char *str) {
DELEGATE *actualdelegate = *pdelegate;

while(actualdelegate != NULL) {
actualdelegate->func(str);
actualdelegate = actualdelegate->next;
}
}

void delegate_del(DELEGATE **pdelegate, void (*funcpointer)(char*)) {
DELEGATE *actualdelegate = *pdelegate;
DELEGATE *aux = NULL;
int found = 0;

if(funcpointer == NULL || actualdelegate == NULL)
return;

if(actualdelegate->func == funcpointer)
{
aux = actualdelegate->next;
free(actualdelegate);
actualdelegate = aux;
}
else {
while(actualdelegate->next != NULL && !found) {
if(actualdelegate->next->func == funcpointer) {
found = 1;
aux = actualdelegate->next->next;
free(actualdelegate->next);
actualdelegate->next = aux;
}
else actualdelegate = actualdelegate->next;
}
}
}

void delegate_free(DELEGATE **pdelegate) {
DELEGATE *aux = NULL;

if(*pdelegate == NULL) return;
while(*pdelegate != NULL) {
aux = (*pdelegate)->next;
free(*pdelegate);
*pdelegate = aux;
}
}

/* FUNCIONES DE PRUEBA */
void a(char *str) {
printf("%p: %s\n", &a, str);
}

void b(char *str) {
printf("%p: %s\n", &b, str);
}

void c(char *str) {
printf("%p: %s\n", &c, str);
}

/* PROGRAMA DE PRUEBA */
int main() {

DELEGATE *midelegado = NULL;

delegate_add(&midelegado, &a);
delegate_add(&midelegado, &b);
delegate_add(&midelegado, &c);

delegate_exec(&midelegado, "hola");

delegate_del(&midelegado, &b);
delegate_exec(&midelegado, "adios");

delegate_free(&midelegado);
midelegado = NULL;

return 0;
}

#15
No es mucha cosa, solo un divertimento; pero sirve para ver en qué parte de la memoria pone el S.O. las funciones, las variables locales, las globales y las dinámicas.
Así se puede ver como el sistema separa la memoria de código, la memoria de pila (stack) y la memoria del montón (heap).


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

char gc;
int gi;

int main(int argc, char *argv[])
{
char c;
int i;
int *p = malloc(sizeof(int));
printf("printf\t= %p\n", &printf);
printf("malloc\t= %p\n", &malloc);
printf("main\t= %p\n", &main);
printf("\n");
printf("gi\t= %p\n", &gi);
printf("gc\t= %p\n", &gc);
printf("\n");
printf("argv\t= %p\n", &argv);
printf("argc\t= %p\n", &argc);
printf("\n");
printf("c\t= %p\n", &c);
printf("i\t= %p\n", &i);
printf("p\t= %p\n", &p);
printf("\n");
for(i = 0; i < argc; ++i)
printf("argv[%i]\t= %p -- %s$\n", i, argv[i], argv[i]);
printf("\n");
printf("p (->)\t= %p\n", p);
free(p);
return 0;
}


P. ej.:

$ ./c 1 12 123 1234 12345
printf   = 0x4004f0
malloc   = 0x400520
main   = 0x40061d

gi   = 0x60105c
gc   = 0x601060

argv   = 0x7ffd71212400
argc   = 0x7ffd7121240c

c   = 0x7ffd71212413
i   = 0x7ffd71212414
p   = 0x7ffd71212418

argv[0]   = 0x7ffd71214551 -- ./c$
argv[1]   = 0x7ffd71214555 -- 1$
argv[2]   = 0x7ffd71214557 -- 12$
argv[3]   = 0x7ffd7121455a -- 123$
argv[4]   = 0x7ffd7121455e -- 1234$
argv[5]   = 0x7ffd71214563 -- 12345$

p (->)   = 0x1e36010
#16
Cuándo se usa la función malloc, por ejemplo, y una llamada básica podría ser algo así:

int *p = malloc(sizeof(int) * 5);

Y ahora viene la parte curiosa y mi planteamiento:

int arr[5] es un array de enteros.
int (*p)[5] es un puntero a un array de 5 enteros.
Lo único que tienen en común los dos son el tipo de dato, int, y el tamaño del array, 5. El nombre que le demos no tiene imporancia. Si se obvia dicho nombre nos debería dar un tamaño pero sin declarar nada.

Por tanto el código antes escrito podría codificarse de una forma un poco más intuitiva:

int *p = malloc( sizeof(int[5]) );

Y funciona, al menos con GCC.

>>> Editado porqué estas líneas no tienen un sentido práctico <<<

También funciona:

int *p = malloc( sizeof(int[5][5]) );

y

int **p = malloc( sizeof(int[5][5]) );


>>>>>>>>>>>>>>>>>>>>>>>><<<<<<<<<<<<<<<<<<<<<<<<<<<

¿Qué os parece?