Saludos a todos. Llevo días con sus noches dándole mil vueltas a esto y en todos los lados que encuentro, leo que la alternativa es hacerlo a mano, pero no sé qué es a mano en este caso.
Mi caso es que tengo que escribir dos nombres con sus dos apellidos, unirlos en una cadena con espacios y ordenarlos lexicográficamente sin utilizar strcmp.
Este es el código que tengo hecho:
#include<stdio.h>
#include<string.h>
#include<conio.h>
//Librerías
int main(void){
int nombre1,nombre2,let,primero=1,segundo=1,iguales=0;
char nom1[50],apuno1[50],apdos1[50],nom2[50],apuno2[50],apdos2[50],esp[1];
//Declaración de variables cadena
strcpy(esp," ");
//Cadena espacio
printf("Nombre de la primera persona: ");
gets(nom1);
printf("\nPrimer apellido de la primera persona: ");
gets(apuno1);
printf("\nSegundo apellido de la primera persona: ");
gets(apdos1);
printf("\nNombre de la segunda persona: ");
gets(nom2);
printf("\nPrimer apellido de la segunda persona: ");
gets(apuno2);
printf("\nSegundo apellido de la segunda persona: ");
gets(apdos2);
//Petición de datos
strcat(nom1,esp);
strcat(nom1,apuno1);
strcat(nom1,esp);
strcat(nom1,apdos1);
strcat(nom2,esp);
strcat(nom2,apuno2);
strcat(nom2,esp);
strcat(nom2,apdos2);
//Concatenación de cadenas
nombre1=strlen(nom1);
nombre2=strlen(nom2);
//Contador de caracteres
if(nombre1<=nombre2){
for(let=0;primero!=0||segundo!=0||iguales!=nombre1;let++){
if(nom1[let]<nom2[let]){
primero=0;
}
else if(nom1[let]>nom2[let]){
segundo=0;
}
else if(nom1[let]==nom2[let]){
iguales++;
}
}
}else{
for(let=0;primero!=0||segundo!=0||iguales!=nombre2;let++){
if(nom1[let]<nom2[let]){
primero=0;
}
else if(nom1[let]>nom2[let]){
segundo=0;
}
else if(nom1[let]==nom2[let]){
iguales++;
}
}
}//Comparación de letras
if(primero==0||iguales==nombre1){
printf("\nLos nombres ordenados son:\n%s\n%s",nom1,nom2);
}else if (segundo==0||iguales==nombre2){
printf("\nLos nombres ordenados son:\n%s\n%s",nom2,nom1);
}else{
printf("\nLos nombres ordenados son:\n%s\n%s",nom2,nom1);
}//Resultado
getche();
return(0);
}
Los nombres los coge bien, y al final están bien unidos en la cadena, pero no los ordena, el primer nombre que escribo es el primero que aparece, y si pongo dos nombres exactamente iguales, me salta un error en la ejecución, aunque compila bien. El compilador que utilizo es el Qt Creator de Nokia, que es el que se utiliza en la universidad.
Espero y agradezco sobremanera cualquier tipo de ayuda.
Usas demasiadas lineas para algo muy simple.
Las cadenas son arrays de caracteres.
Como las cadenas a comparar no son constantes, puedes hacer un bucle que cuente la longitud de la cadena, y luego otro bucle que vaya comparando los sucesivos elementos del array hasta que encuentre alguno diferente (si lo encuentra...)
Buenas. ¿Lo de los bucles me ha parecido entender que ponga un for (por ejemplo) para contar caracteres y otro para somprarar letras?
Para contar caracteres tengo el strlen metido en las variables nombre1 y nombre2, para que si una cadena es más corta, mediante la variable iguales cuente las que son iguales hasta que finalice la cadena más corta, con lo que se saldría del bucle de comparación.
He vuelto a reescribir esa parte, en lugar de con <, >, o ==, restando los caracteres y la diferencia, según sea mayor, menor o igual que cero, un poco al estilo strcmp.
Poniendo caracteres arbitrariamente fuera de cualquier bucle, la resta me la hace perfecta, si la primera es G y la segunda B, el resultado es 5, y si son B y G, me da -5. Eso es lo que yo necesito para resolver el programa.
Pues bien, al aplicarlo poniendo una variable tal que así nom1[let] la resta siempre es 0, por eso no me reordena nada. Y nuevamente, si pongo dos cadenas exactamente iguales, compila sin problemas, pero a la hora de entrar en el bucle, salta un error de ejecución.
Este es el nuevo código, aunque es muy parecido al anterior:
#include<stdio.h>
#include<string.h>
#include<conio.h>
//Librerías
int main(void){
int dif,long1,long2,let,same=0,prim,seg;
char nom1[50],apuno1[50],apdos1[50],nom2[50],apuno2[50],apdos2[50],esp[1];
//Declaración de variables cadena
strcpy(esp," ");
//Cadena espacio
printf("Nombre de la primera persona: ");
gets(nom1);
printf("\nPrimer apellido de la primera persona: ");
gets(apuno1);
printf("\nSegundo apellido de la primera persona: ");
gets(apdos1);
printf("\nNombre de la segunda persona: ");
gets(nom2);
printf("\nPrimer apellido de la segunda persona: ");
gets(apuno2);
printf("\nSegundo apellido de la segunda persona: ");
gets(apdos2);
//Petición de datos
strcat(nom1,esp);
strcat(nom1,apuno1);
strcat(nom1,esp);
strcat(nom1,apdos1);
strcat(nom2,esp);
strcat(nom2,apuno2);
strcat(nom2,esp);
strcat(nom2,apdos2);
//Concatenación de cadenas
long1=strlen(nom1);
long2=strlen(nom2);
//Contador de caracteres
if(long1<=long2){
for(let=0;prim!=0||seg!=0||same!=long1;let++){
dif=nom1[let]-nom2[let];
if(dif>0){
prim=0;
}else if(dif<0){
seg=0;
}else{
same++;
}
}
}else{
for(let=0;prim!=0||seg!=0||same!=long2;let++){
dif=nom1[let]-nom2[let];
if(dif>0){
prim=0;
}else if(dif<0){
seg=0;
}else{
same++;
}
}
}//Comparación de caracteres
printf("Iguales: %d",same);
printf("Diferencia: %d",dif);
printf("\nPrimer nombre: %s\nSegundo nombre: %s",nom1,nom2);
getche();
return(0);
}
Los printf del final están sólamente a modo de comprobación de datos, no muestran el resultado que necesito, ya que las restas no se hacen como deberían.
Te dejo un ejemplo:
#include<stdio.h>
#include<string.h>
//Compara cadenas - by pablomi
int main()
{
int i, comparacion;
char cadena1[50] = "Hola";
char cadena2[50] = "Adios";
for(i=0;i<strlen(cadena1);i++){
if(cadena1[i]!=cadena2[i])
comparacion = 1;
else
comparacion = 0;
}
if(comparacion==1)
printf("Son distintas\n");
else
printf("Son iguales\n");
return 0;
}
Vale, vale. Ya me va saliendo. Pero aún queda algo que depurar, ya que al meter como primer nombre "bb bb bb" y como segundo "bbb bbb bbb", me ordena como primero el largo y luego el corto, cuando tendría que ser al revés.
Esta es la parte del código cambiada:
for(let=0;let<strlen(nom1);let++){
if(nom1[let]!=nom2[let]){
comp=1;
}else
comp=0;
}
//Comparación de cadenas
if(comp==1){
for(let=0;let<strlen(nom1);let++){
if(nom1[let]<nom2[let]){
ord=1;
}else if(nom2[let]<nom1[let]){
ord=2;
}
}
}else{
printf("\nNombres ordenados:\n%s\n%s",nom1,nom2);
}//Comparación de letras
if(ord==1){
printf("\nNombres ordenados:\n%s\n%s",nom1,nom2);
}else if(ord==2){
printf("\nNombres ordenados:\n%s\n%s",nom2,nom1);
}//Muestra de resultado
¿Debería crear un bucle comparador según si el strlen de la primera cadena es más largo que el segundo y viceversa, o hay algún otro modo que consuma menos recursos y ocupe menos líneas?
Cita de: pablomi en 24 Octubre 2010, 20:22 PM
Te dejo un ejemplo:
Codigo
Cuidad con tu codigo, si la ultima letra de cada cadena coincide dice que son iguales, ej
Holaaaaaaaaaaaa
Nadaqueveraaaaa
#include<stdio.h>
#include<string.h>
//Compara cadenas - by pablomi
int main()
{
int i, comparacion = 0;
char cadena1[50] = "Hola";
char cadena2[50] = "Adios";
for(i=0;i<strlen(cadena1);i++){
if(cadena1[i]!=cadena2[i])
comparacion = 1;
if(comparacion==1)
printf("Son distintas\n");
else
printf("Son iguales\n");
return 0;
}
ahi quedaria bien
Fijate de corregir eso, rockmore
Btw: Tene en cuenta que el strcmp ordena esciimente, no alfabeticamente
Para el strcmp
Belen va antes que
ana porque en el ascii las mayusculas estan primero
Cita de: Rockmore en 24 Octubre 2010, 22:33 PM
¿Debería crear un bucle comparador según si el strlen de la primera cadena es más largo que el segundo y viceversa, o hay algún otro modo que consuma menos recursos y ocupe menos líneas?
yo en tu lugar usaria una variable donde guardo la cantidad de letras que tiene la cadena mas corta, y uso esa variable para las vueltas del for
Casi, casi. Si las cadenas son distintas, ordena de lujo. Si son iguales, se fija en la última letra: "aaa aaa aaa" va antes que "bbb bbb bbb", pero "bbb bbb bba" va antes que "aaa aaa aab"
long1=strlen(nom1);
long2=strlen(nom2);
if(long1<=long2){
longdef=long2;
}else{
longdef=long1;
}//Contador de caracteres
for(let=0;let<longdef;let++){
if(nom1[let]!=nom2[let]){
comp=1;
}
}//Comparación de cadenas
if(comp==1){
for(let=0;let<longdef;let++){
if(nom1[let]<nom2[let]){
ord=1;
}else if(nom2[let]<nom1[let]){
ord=2;
}
}
}//Comparación de letras
if(ord==1){
printf("\nNombres ordenados:\n%s\n%s",nom1,nom2);
}else{
printf("\nNombres ordenados:\n%s\n%s",nom2,nom1);
}//Muestra de resultado
getche();
return(0);
}
Este código es cada vez más surrealista. Había pensado en poner algún tipo de contador, o una condición que rompiese el bucle, de modo que la primera condición que cambie alguna variable, se quedase así, como en el primer código que hice:
for(let=0;ord!=1&&ord!=2&&let<longdef;let++)
Edit: Justo eso era lo que necesitaba. Ahora sí que creo que está impecable. Gracias a todos por las indicaciones
EDITO:
volviendo a mirar tu codigo, note
if(comp==1){
for(let=0;let<longdef;let++){
if(nom1[let]<nom2[let]){
ord=1;
}else if(nom2[let]<nom1[let]){
ord=2;
Estas teniendo el mismo problema que pablomi
Vos tenes que poner la variable en un estado, y cambiarlo si encuentra letras que no coincide, pero no volver a ponerle en el estado inicial si encuentra despues coincidencias
Si no interpreto mal, esa parte de codigo hace que lo unico que importe son, la ultima letra de la cadena corta, y la de la misma posicion de la larga, dependiendo de esas dos te va a ordenar las cadenas
Lo arreglas poniendole el for que mencionas, porque cuando ord pasa a valer 1 o 2, el for deja de correr, deja el codigo como lo posteaste y ponele un "break;" abajo de ord=1; y ord=2;
eso hace que cuando encuentre 2 letras distintas, guarde en ord cual de los 2 mostras primero y el break te saca del ciclo for, y no necesitas complicar las condiciones del for
¡Buenas!
hace mucho que no pongo codigos... pero viendo que la gente se anima...
/*
* mystrcmp < 0 si s1 < s2
* mystrcmp ==0 si s1 == s2
* mystrcmp > 0 si s1 > s2
*/
int mystrcmp(char* s1,char* s2)
{
for(; *s1 && *s2 && (*s1) == (*s2) ; s1++ , s2++);
return ((*s1) - (*s2));
}
Eso si trabajas con funciones, sino en tu codigo podrias poner
for(i = 0 ; nom1[i] && nom2[i] && nom1[i] == nom2[i] ; i++);
ord = nom1[i] - nom2[i]; /* y ord tendra los valores de la funcion anterior */
Espero no haberme confundido, ya que ni siquiera he probado el codigo... :silbar:
¡Saludos!
Cita de: do-while en 25 Octubre 2010, 03:45 AM
for(i = 0 ; nom1[i] && nom2[i] && nom1[i] == nom2[i] ; i++);
ord = nom1[i] - nom2[i]; /* y ord tendra los valores de la funcion anterior */
No entiendo como definiste el for, me explicas?
Paso por paso.
El for no tiene cuerpo, todas las comprobaciones se hacen en la condicion de continuidad. (Date cuenta de que nada mas terminar la declaracion del for, hay un punto y coma, por lo tanto el valor se le asigna a ord al salir del for)
Cualquier cadena termina en cero, y cero en C significa falso y distinto de cero verdadero. Por lo tanto
nom1[k] && nom2[k]
significa que for se ejecutara mientras las dos cadenas tengan un caracter, o lo que es lo mismo, que el for finalizara cuando se acabe una de las dos cadenas (o las dos).
La siguiente condicion te dice que el for continuara mientras las letras de la posicion actual sean iguales.
Es decir, de todas todas se saldra del for si alguna de las cadenas ha terminado o si el caracter de la posicion i es distinto.
(cambio la i por la k para que no me salga en cursiva)
Caso1: nom1 ha terminado
En este caso, nom1[k] == 0, por lo tanto si la segunda cadena es mas larga, 0 - letra (no simbolo, sino letra) sera menor que cero. Y si la segunda cadena tambien ha terminado, las dos seran iguales:
Hola
Holaa
o sino
Hola
Hola
(compruebalo mirando las condiciones del for con lapiz y papel)
Caso2: nom2 ha terminado
Si se da este caso, nom1 no habra terminado (estudia sobre la evaluacion del y logico), pero nom2 si, por lo tando nom1[k]!=0 y nom2[k] == 0, suponiendo que nom1[k] es una letra del alfabeto, se tiene que nom1[k] > 0 y nom2[k] == 0. Es decir, nom1[k] - nom2[k] > 0, lo cual tiene su logica, ya que todas las letras de nom1 seran iguales a las de nom2 mientras no se termine nom2, pero nom1 sera mas larga:
Holaa
Hola
(como antes, comprueba con lapiz y papel que efectivamente es asi)
Caso3: nom1[k] != nom2[k]
Ahora no ha terminado ni nom1, ni nom2 y se ha encontrado una letra diferente en las cadenas. Por lo tanto nom1[k] - nom2[k] sera menor o mayor que cero, segun nom1[k] sea menoro o mayor alfabeticamente que nom2[k].
(como siempre, compruebalo con lapiz y papel)
¡Saludos!
Entiendo, pero la pregunta era por:
(i = 0 ; nom1[i ] && nom2[i ] && nom1[i ] == nom2[i ] ; i++)
el for va a seguir corriendo mientras nom1 en la posicion i, que?
el resto lo entiendo
Edito:
Relei tu post a ver si entendia, y creo que entendi, o sea
nom1[i ] && nom2[i ]
es equivalente a poner
nom1[i ] != 0 && nom2[i ] != 0 ?
Si es eso ya entendi todo y corto con el off :P
Eso mismo es, como en C no hay booleanos, una expresion que vale cero es falso, y una que es distinta de cero sera verdadero.
Por lo tanto poner
for(i=0 ; s[i] ; i++)
es equivalente a poner
for(i=0 ; s[i] != 0 ; i++)
¡Saludos!
Una cosa mas, si en lugar de tomar como valor de la comparacion
ord = nom1[i] - nom2[i];
tomas
ord = (unsigned char)nom1[i] - (unsigned char)nom2[i];
Te olvidas de los problemas que te pueden dar los simbolos y siempre que una cadena sea mas larga que otra tendras un valor positivo o negativo segun sea la primera o la segunda mas larga.