PDA

View Full Version : Help C Programm in Xcode




crazyjorgito
Aug 27, 2013, 12:34 PM
Hello guys, I have a problem with my C code, hope you can help me. The program is about making a basic book "database".
When I run the following code (in Xcode), I don't know why the following sentence gets skipped:

gets(nombre[i]);

On the terminal it directly prints the following if I take option 1 from the menu:

Bienvenido al catalogo de libros.

Catalogo de tarjetas:
1. Introducir
2. Buscar por autor
3. Buscar por titulo
4. Salir

Elija opcion:1
warning: this program uses gets(), which is unsafe.

Introduzca el nombre del libro:Introduzca el autor del libro:

This is the full code (not long):

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

#define MAX 100

char nombre[MAX][20];
char autor[MAX][20];
char edit[MAX][20];
char buscar[20];
char buscar_t[20];
char buscar_a[20];


int opcion,i,j,k,l;

void menu(void);
void intro(void);
void buscar_autor(void);
void buscar_tit(void);
void salir(void);

void main(void)
{
printf("Bienvenido al catalogo de libros. \n");
menu();
}




void menu(void)
{
printf("\n Catalogo de tarjetas:");
printf("\n 1. Introducir");
printf("\n 2. Buscar por autor");
printf("\n 3. Buscar por titulo");
printf("\n 4. Salir");

printf("\n Elija opcion:");
scanf("%d", &opcion);

switch (opcion) {
case 1:
intro();
break;
case 2:
buscar_autor();
break;
case 3:
buscar_tit();
break;
case 4:
salir();
break;

}


}

void intro(void)
{
for (i=0; i<MAX; i++)
{
printf("Introduzca el nombre del libro:");
gets(nombre[i]);

if (!strcmp(nombre[i],"salir"))
{
break;
}

printf("Introduzca el autor del libro:");
gets(autor[i]);
printf("Introduzca la editorial del libro:");
gets(edit[i]);
}

menu();

}

void buscar_tit(void)
{
printf("Introduzca el titulo del libro que quiera buscar:");
gets(buscar_t);

for (j=0; j<MAX+1; j++)
{
if (!strcmp(nombre[j],buscar_t))
{
printf("El libro se ha encontrado, el titulo es %s. ", nombre[j]);
break;
}
if (j=MAX)
{
printf("El libro no se ha encontrado.");
break;
}

}

}

void buscar_autor(void)
{
printf("Introduzca el autor del libro que quiera buscar:");
gets(buscar_a);

for (k=0; k<MAX+1; k++)
{
if (!strcmp(autor[k],buscar_a))
{
printf("El libro se ha encontrado, el titulo es %s. ", nombre[k]);
break;
}
if (k=MAX)
{
printf("El autor no se ha encontrado.");
break;
}
}
}

void salir(void)
{
printf("Muchisimas gracias por usar el catalogo de libros. \n");
}

Hope you can help me figure out the error.

Thanks guys.



chown33
Aug 27, 2013, 01:20 PM
Look carefully at the format string in your scanf() call. Then read this post from one of your earlier threads (http://forums.macrumors.com/showpost.php?p=15896079&postcount=7).

Here's the relevant content:
Your scanf only ate the number but not the trailing newline. Putting a newline or white space after the %d will then give you the opposite problem, reading too far.

This is why people don't like scanf.

I would suggest reading an actual line (use fgets(3)) and then using sscanf() to scan the string.

I also suggest following the recommendation of another post from that thread: make small isolated test programs that test specific things. In this case, test the scanf() you posted followed by gets().

crazyjorgito
Aug 28, 2013, 05:43 AM
Thank you very much. True, until know it didn't happen to me so I absolutely forgot. I will work on it right now and hope to solve the problem, thank you very much.

crazyjorgito
Aug 28, 2013, 06:08 AM
Look carefully at the format string in your scanf() call. Then read this post from one of your earlier threads (http://forums.macrumors.com/showpost.php?p=15896079&postcount=7).

Here's the relevant content:
Your scanf only ate the number but not the trailing newline. Putting a newline or white space after the %d will then give you the opposite problem, reading too far.

This is why people don't like scanf.

I would suggest reading an actual line (use fgets(3)) and then using sscanf() to scan the string.

I also suggest following the recommendation of another post from that thread: make small isolated test programs that test specific things. In this case, test the scanf() you posted followed by gets().

Ok, so i've tested my scanf("%d", &opcion); using a printf("%d", opcion); right after to proove that scanf reads correctly my input.
Surprisingly, it reads the option I introduce correctly. Moreover, i've tried running the program with no "\n" in any part to see if gets(nombre[i]) works but still it gets jumped...

Any ideas?

chown33
Aug 28, 2013, 12:01 PM
Ok, so i've tested my scanf("%d", &opcion); using a printf("%d", opcion); right after to proove that scanf reads correctly my input.
Surprisingly, it reads the option I introduce correctly. Moreover, i've tried running the program with no "\n" in any part to see if gets(nombre[i]) works but still it gets jumped...

Any ideas?

Post the revised version of the code.

Also, go back and reread your earlier thread. The one I linked to above. Carefully reread the posts and links I gave. Make sure you understand what your scanf() is doing, and what it isn't doing. You may have to read the man page for scanf().

crazyjorgito
Aug 28, 2013, 12:06 PM
I've made the sentences using \n as comments just to prove that scanf("%d", &opcion) works. Therefore, if there are no spaces after, gets(nombre[i]) should work, right?

Here it goes:





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

#define MAX 100

char nombre[MAX][20];
char autor[MAX][20];
char edit[MAX][20];
char buscar[20];
char buscar_t[20];
char buscar_a[20];


int opcion,i,j,k,l;

void menu(void);
void intro(void);
void buscar_autor(void);
void buscar_tit(void);
void salir(void);

void main(void)
{
printf("Bienvenido al catalogo de libros.");
menu();
}




void menu(void)
{
//printf("\n Catalogo de tarjetas:");
//printf("\n 1. Introducir");
//printf("\n 2. Buscar por autor");
//printf("\n 3. Buscar por titulo");
//printf("\n 4. Salir");

printf("Elija opcion:");
scanf("%d", &opcion);
printf("%d", opcion);




switch (opcion) {
case 1:
intro();
break;
case 2:
buscar_autor();
break;
case 3:
buscar_tit();
break;
case 4:
salir();
break;

}


}

void intro(void)
{
for (i=0; i<MAX; i++)
{
printf("Introduzca el nombre del libro:");
gets(nombre[i]);

if (!strcmp(nombre[i],"salir"))
{
break;
}

printf("Introduzca el autor del libro:");
gets(autor[i]);
printf("Introduzca la editorial del libro:");
gets(edit[i]);
}

menu();

}

void buscar_tit(void)
{
printf("Introduzca el titulo del libro que quiera buscar:");
gets(buscar_t);

for (j=0; j<MAX+1; j++)
{
if (!strcmp(nombre[j],buscar_t))
{
printf("El libro se ha encontrado, el titulo es %s. ", nombre[j]);
break;
}
if (j=MAX)
{
printf("El libro no se ha encontrado.");
break;
}

}

}

void buscar_autor(void)
{
printf("Introduzca el autor del libro que quiera buscar:");
gets(buscar_a);

for (k=0; k<MAX+1; k++)
{
if (!strcmp(autor[k],buscar_a))
{
printf("El libro se ha encontrado, el titulo es %s. ", nombre[k]);
break;
}
if (k=MAX)
{
printf("El autor no se ha encontrado.");
break;
}
}
}

void salir(void)
{
printf("Muchisimas gracias por usar el catalogo de libros. \n");
}

chown33
Aug 28, 2013, 01:19 PM
First, you should have already read the man page for scanf(). If you haven't done so, do it now:
https://developer.apple.com/library/mac/documentation/Darwin/Reference/ManPages/man3/scanf.3.html

If you have read scanf's man page, then reread this part:
Each successive pointer argument must correspond properly with each successive conversion specifier
(but see the * conversion below). All conversions are introduced by the % (percent sign) character.
The format string may also contain other characters. White space (such as blanks, tabs, or newlines)
in the format string match any amount of white space, including none, in the input. Everything else
matches only itself. Scanning stops when an input character does not match such a format character.
Scanning also stops when an input conversion cannot be made (see below). [Underline added]


Now look at the format string you have in your scanf():
printf("Elija opcion:");
scanf("%d", &opcion);
printf("%d", opcion);

Your format string contains only a conversion. There is no white space character.

Next, consider that when you type input in, you enter a series of digits followed by a newline. The newline is what tells scanf to proceed with reading and scanning. That newline remains in the stdin input buffer until something reads it. So is there a white space character in scanf's format string that will read the newline during scanf's scanning?

If the newline isn't read by scanf, it remains in the input buffer for something else to read. If there's a newline waiting in the input buffer when gets() is eventually executed, what do you think it reads? What does your code do if gets() reads an empty line?

The reason the newline remains in the input buffer is precisely because you have no white space characters in your format string. So think about where you ought to put a white space character in your format string, so it will consume the newline. Once you've thought it through, make a test and run it.


Next, instead of using gets(), follow the recommendation of using fgets() followed by sscanf(). You should read the man page for fgets() first, so you know how it works. Here's the home page for all of OS X's online man pages:
https://developer.apple.com/library/mac/documentation/Darwin/Reference/ManPages/

The man page for fgets will be in section 3.


Note that this is exactly the same problem you had in your earlier thread, the one I linked to in my first reply. Not just similar, but exactly the same.

If you solved the problem there, you should be able to solve the problem here. If you've forgotten what you did, go back and look at your older code. If you didn't solve the problem, then what did you do to make the older code work? Or did you just give up?

I suspect you haven't read any reference documentation for scanf, so you didn't really know how it works. If your book told you to use it, it should have explained how it works. If the book didn't tell you to use it, then you should read documentation and write simple test programs so you understand how a function works before using it in a real program.

crazyjorgito
Aug 29, 2013, 06:12 AM
Thank you very much, I've read the man for scanf and fgets and I'm still trying to understand them.
Therefore, I've tried to solve the problem (which I couldn't) using the scanf sentence like this:

scanf(" %d", &opcion);

And using fgets instead of gets like this:

fgets(nombre[i], 20, stdin);

Also, as this didn't work, also I tried different combinations of the scanf sentence moving around the spaces.

Moreover, for the other program I used another method which solved my problem.

Hope you can guide me a little bit further.

chown33
Aug 29, 2013, 01:04 PM
Moreover, for the other program I used another method which solved my problem.

What was that method? Post the code, and describe it.

Why not use that method here?

crazyjorgito
Aug 29, 2013, 01:37 PM
What was that method? Post the code, and describe it.

Why not use that method here?

What I did was substitute getchar for the following:

int opción;
scanf ("%d", &opcion);
donde 1 es si y 0 es no y verás que funciona.


This way it worked. Anyway, I'm really willing to understand and solve my problem. I really don't know what to try, i'm willing to use the switch function. As I said before from what I understood from the manual, I should of advanced a little bit but i'm still at the same point.

So please give me some clues. Thanks.

chown33
Aug 29, 2013, 02:22 PM
As I said before from what I understood from the manual
Which manual do you mean? man pages? Something else?

So please give me some clues. Thanks.

As far as I can tell, you haven't written any simple test programs yet. Specifically, small programs that only test scanf() and gets() in that order. If you have written them, then you haven't posted their code or their results.

You also haven't told us exactly what "moving around the spaces" means. You haven't posted the results of running those versions, nor described how those results differ from the results of running other test programs with different scanf format strings.

What you have done is modify your existing program, but that's not exactly simple or clear. You also haven't posted any results indicating that you've tried more than a few variations.

Even with a modified existing program, you haven't described much of what actually happened. You've simply said "It didn't work", without telling us what actually happened.

You also haven't said whether there are different ways that the various changes don't work. "Not working" is too vague; there are many ways something can not work. Having that information can lead to an understanding of why something happens.

In my first reply, I quoted this from your earlier thread:
I would suggest reading an actual line (use fgets(3)) and then using sscanf() to scan the string.

Have you written or tested anything like that?

In short, you haven't been systematic in exploring or documenting exactly what you're doing.


One reason I'm prompting you to systematically make and run these simple test programs, with a careful record of the results, is because if you don't do that work then I have to. Right now, I don't have the time to dedicate to writing and running a half-dozen or more test programs.