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ú

Mensajes - Yoel Alejandro

#201
Así es, el carácter nulo '\0' es de tipo char, mientras que "\0" es una cadena, o sea que es tipo char*, un puntero. Por eso, estrictamente hablando, son cosas diferentes.

#202
Programación C/C++ / Re: Problema con loop
2 Marzo 2014, 20:38 PM
Más clara imposible la explicación de por qué se llama "array de arrays" de caracteres.

De acuerdo también con el aporte de leosansan de verificar la integridad del dato suministrado por el usuario, y limpiar el búfer de entrada descartando los caracteres encontrados hasta llegar al fin de línea.

Creo que no tengo aportes que hacer a este tema ... ya se ha dicho todo, al menos al nivel que requiere quién inició la pregunta.
#203
Claro, el error no tiene que ver con el float, sino con el uso de métodos de E/S de C++ (cout, endl) que requieren como ya te dijeron declarar "using namespace std"

Y concuerdo también en que debes estar atento a los mensajes del compilador, con el tiempo serás diestro en interpretarlos y saber exáctamente a qué parte del programa se refieren.
#204
Hola, supongo que tu intención es que la función "uno" tome su parámetro y se lo pase a la función "dos". En ese caso, me voy a tomar la libertar de cambiar el nombre del miembro entero de la estructura numero de "n" a "x". Pues tienes un uso duplicado de nombres que si bien no es un error, puede resultar confuso. Así quedaría:

Código (cpp) [Seleccionar]

#include<stdio.h>
typedef struct
{
 int x;
}numero;


También te aconsejaría que cuando el argumento se refiera a un puntero, uses un sufijo distintivo como "Ptr", o "_ptr". Quedaría entonces:

Código (cpp) [Seleccionar]

void uno (numero *n_ptr);
void dos (numero *n_ptr);


Ahora vamos al centro del problema. En C todos los argumentos de las funciones se pasan por valor. Es decir, se pasa como argumento de la función una copia del valor de la variable. Pero se puede simular el paso por referencia, dando como argumento la dirección de la variable en cuestión (ésto eso, se pasa un puntero a dicha variable). Lo cual permite alterar directamente la variable al manipular en el área de memoria ocupada por ésta. Sólo ten en cuenta que en el código de la función debes usar el operador de indirección "*" para acceder al contenido de la variable, apuntado por la dirección suministrada.

Por ejemplo, supongamos que "uno" pasa el valor de su argumento (un puntero) a "dos", la cual modifica el valor del campo x de la estructura referenciada. Entonces sería

Código (cpp) [Seleccionar]

main()
{
 numero n;
 uno(&n);
}

void uno (numero *n_ptr)
{
  dos (n_ptr);    // se pasa una copia del puntero a "dos"
}

void dos (numero *n_ptr)
{
   (*nptr).x += 1;
}


Observa que en el código de "dos" se accede al contenido apuntado por n_ptr (el contenido de la variable n) por medio de (*n_ptr). Se requieren los paréntesis porque el operador "." tiene mayor prioridad que el "*", y de no colocarlos se interpretaría *(n_ptr.x) que es incorrecto pues n_ptr es un apuntador y no una estructura.

Por último, aquí puedes ver el código completo y al compilar y ejecutar verás que aunque hemos puesto inicialmente el valor de n.x en 3, al final termina siendo 4  :D

Código (cpp) [Seleccionar]

#include<stdio.h>

typedef struct
{
 int x;
}numero;

void uno (numero *n_ptr);
void dos (numero *n_ptr);

main()
{
 numero n;
 n.x = 3;
 printf ("antes n.x era: %d\n", n.x);
 uno (&n);
 printf ("ahora n.x es: %d\n", n.x);
}

void uno (numero *n_ptr)
{
  dos (n_ptr);    // se pasa una copia del puntero a "dos"
}

void dos (numero *n_ptr)
{
   (*n_ptr).x += 1;
}

#205
Ah, ..... y no uses system("PAUSE"). Las órdenes system dependen su comportamiento del sistema operativo por lo que pueden hacer el programa "no portable" entre distintas máquinas. En su lugar usa getchar() que es una función estándar de C y por lo tanto tiene un comportamiento bien definido.
#206
Programación C/C++ / Re: Macros en C
14 Febrero 2014, 21:07 PM
Así mismo es m@o_614, el preprocesador de C sustituye cada aparición del identificador o nombre de la macro por el texto de reemplazo que haya sido definido. El texto final obtenido es pasado al compilador (obviamente para que lo compile, jeje).

Una aplicación puede ser si tienes un programa donde se define un valor que aparece muchas veces en el mismo. Si quieres cambiar ese parámetro, tendrías que editar manualmente sus apariciones. Por ejemplo, quieres leer un total de digamos 3 enteros dados por el usuario y formar un vector o arreglo con ellos y luego imprimir el valor de dichos elementos:

Código (cpp) [Seleccionar]

#include <stdio.h>
#include <stdlib.h>
 
int main(void)
{
int i, x[3];

/* pedir numeros al usario */
for ( i = 0; i < 3; i++ ) {
printf( "Intro valor %d: ", i+1);
scanf( "%d", &x[i] );
getchar();
}

/* imprimiendo contenido del arreglo */
for ( i = 0; i < 3; i++ ) {
printf( "Valor %d: %d\n", i+1, x[i] );
}

return EXIT_SUCCESS;
}


Observa que el valor "3" aparece tres veces en el código. Si quisieras modificar tu programa para que reciba no 3 sino 5 valores, tendrías que editar en dos líneas diferentes de dicho código. Una alternativa sería definir una constante simbólica N, e indicar que cada aparición suya debe reemplazarse por el valor 3:

Código (cpp) [Seleccionar]

#include <stdio.h>
#include <stdlib.h>
 
#define N 3
 
int main(void)
{
int i, x[N];

/* pedir numeros al usario */
for ( i = 0; i < N; i++ ) {
printf( "Intro valor %d: ", i+1);
scanf( "%d", &x[i] );
getchar();
}

/* imprimiendo contenido del arreglo */
for ( i = 0; i < N; i++ ) {
printf( "Valor %d: %d\n", i+1, x[i] );
}

return EXIT_SUCCESS;
}


Si quieres que el programa reciba 5 valores sólo debes cambiar una línea y poner #define N 5

Las instrucciones #define no van terminadas en punto y coma, puesto que no son instrucciones de asignación de valor a una variable, sino un reemplazo formal de texto en el código fuente.
#207
Acabo de ver que este tema fue respondido al usuario en otro foro de C.
#208
Lo que plantea eferion es verdad. Una buena manera (sencilla) de limitar la longitud de la cadena de entrada es usar fgets (es lo mismo que explican en el post referenciado). Su prototipo es

Código (cpp) [Seleccionar]

fgets( char * buffer, int N, FILE * stream );


donde buffer es la cadena donde será copiada la entrada, N es la mayor cantidad de caracteres copiados al array incluyendo el nulo de terminación (por lo que leerá máximo N-1 caracteres), y stream es el flujo o archivo de donde leerá los datos. Debemos poner "stdin" para lea de la entrada estándar (teclado).

De este modo, reemplaza la sentencia

Código (cpp) [Seleccionar]

scanf("%s", nombre);


por

Código (cpp) [Seleccionar]

#define N 40
char nombre[N];

fgets( nombre, N, stdin );


que leerá máximo 39 caracteres de la entrada estándar.
#209
Excelente eferion  ;-)

En lo particular yo soy un purista de C (y la programación de bajo nivel), pero voy a a tratar de incursionar un poco en las clases contenedoras predefinidas de C++. Si son estándares y altamente conocidas, vale la pena empezar a usarlas jeje.
#210
Programación C/C++ / Re: problema con sprintf
11 Febrero 2014, 03:01 AM
Una observación, la función fgets() es más segura por cuánto permite limitar la longitud de la cadena recibida (el argumento MAX que le pasas), y así prevenir un desbordamiento del búfer. Una verificación que no hacen ni gets() ni scanf(). De hecho, algunos compiladores advierten sobre el uso riesgoso de gets() , desaconsejando su uso.

Yo en su lugar seguiría usando fgets() pero "recortaría" la cadena:

Código (cpp) [Seleccionar]

if ( ( len = strlen( nombre ) ) > 0 && nombre[len - 1] = '\n') nombre[len - 1] = '\0';


Ahora, respecto a que quieres pasar el nombre del archivo sin distinguir mayúsculas y minúsculas lo veo un poco más difícil. Obviamente, no te vas a poner a probar todas las combinaciones de minúsculas y mayúsculas, a ver si alguna abre el archivo (jeje)

A mi se me ocurre listar el contenido del directorio, y probar nombre por nombre contra el nombre dado por el usuario. Si alguno coincide (despreciando mayúsculas y minúsculas), abrir el fichero. Para eso, se requiere un compilador que implemente la biblioteca <unistd.h> la cual obedece un estándar llamado POSIX. Es hecho que sea estándar significa que con seguridad la tienes en una implementación de C para Linux, pero no necesariamente en Windows  :silbar: (ya saben como es Microsoft, rompe-estándares).  

¿Usas Windows verdad? En ese caso, compila con IDE libre para Windows como Dev-Cpp, o MinGW con gcc/g++. No estoy seguro que Borland C lo soporte (la verdad no tengo idea, pues no uso ni Windows ni Borland, jeje).

Bueno, a lo nuestro.
Código (cpp) [Seleccionar]

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <dirent.h>
#include <ctype.h>

#define MAX 40

char * str_to_lower( char *);

int main()
{
FILE *fd = NULL;
char name[MAX];
unsigned long len;
char ready;

char dir_name[100]; /* nombre de directorio */
DIR * dir_ptr = NULL; /* apuntador a directorio */
struct dirent * dirent_ptr; /* estructura 'directory-entry' */
char * f_name; /* name de cada fichero leído en el directorio */

printf("Que archivo quieres abrir: ");

fgets( name, MAX, stdin );
/* quitamos el '\n' al final de la cadena */
if ( ( len = strlen( name ) ) > 0 && name[len - 1] == '\n' )
name[len - 1] = '\0';
strcat( name, ".txt" ); /* añadimos '.txt' al final */

/* pongamos el directorio como el actual, puedes cambiarlo xD */
strcpy( dir_name, ".");

/* 'abrimos' el directorio para leer su contenido */
if ( ( dir_ptr = opendir( dir_name ) ) == NULL ) {
printf( "No existe o no se pudo abrir el directorio '%s'\n", dir_name );
return -1;
}

/* ahora recorremos todo el directorio, buscando
* names de fichero que coincidan */
ready = 0;
while ( ( dirent_ptr = readdir( dir_ptr ) ) != NULL ) {
f_name = dirent_ptr -> d_name;

/* verificamos omitiendo mayúsculas y minúsculas */
if ( ! strcmp( str_to_lower(name), str_to_lower(f_name) ) )
if((fd = fopen(f_name, "r")) != NULL) {
printf("Se abrio '%s'\n", f_name);
ready = 1;
}
}

/* y si al finalizar el ciclo no encontro, emitir error */
if ( !ready )
printf("No se pudo abrir el archivo\n");

/* cerramos el directorio, y el fichero */
if ( dir_ptr != NULL ) closedir( dir_ptr );
if ( fd != NULL ) fclose( fd );

return 0;
}

/* Pasa todos los caracteres de la cadena a minúsculas */
char * str_to_lower( char * s ) {

size_t k = 0;

while ( s[k] != '\0' ) {
if ( isalpha( s[k] ) ) s[k] = tolower( s[k] );
k++;
}

return s;
}


Este programa es funcional, sólo necesita ser compilado y probado. Por ejemplo, yo tengo el mi directorio un file1.txt, y al pasarle el nombre 'FiLe1' me dice que lo abrió. Al pasarle 'FilE2' no lo abre, porque no tengo 'file2.txt'.

Como ves, recorremos todo el directorio y convertimos sus nombres a minúsculas usando las funciones de biblioteca isaplha() (prueba si es una letra), y tolower() (pasa una letra a minúscula).

Lo de recorrer directorio requiere conocer acerca de la estructura dirent y la función readdir. Yo escribí un post al respecto el otro foro, te invito a leerlo para comprender esto mejor: http://foro.chuidiang.com/ccplusplus-linux/listar-contenido-de-un-directorio-usando-funciones-posix-de-c/

Se esperan comentarios, opiniones, etc .....  :)