Page 2 of 2 First 12
  • Jump to page:
    #16
  1. Contributing User
    Devshed Supreme Being (6500+ posts)

    Join Date
    Jan 2003
    Location
    USA
    Posts
    7,145
    Rep Power
    2222
    After migrating declarations to the top of the function:
    C:TEST>gcc -Wall hooby3.c
    hooby3.c: In function `addclient':
    hooby3.c:52: warning: format argument is not a pointer (arg 2)
    hooby3.c:54: warning: format argument is not a pointer (arg 2)

    C:TEST>
    Warnings point you to problems. Never ignore warnings.

    Line 52: scanf("%d", cli->age);
    Line 54: scanf("%d", cli->gsm);

    scanf must be given an address! When it has performed a conversion, it needs to know where to store the results, which means that it needs a memory address. That can be provided either by a pointer or by the address operator (&). You need to use the address operator here!

    scanf("%s", cli->nom);
    Why no address operator here? Because cli->nom is already a pointer, which provides an address.

    However, what does cli->nom point to? We don't know, because it hasn't been initialized yet. It contains garbage and hence could be pointing anywhere, but no direction it points in is safe.

    As I already explained, you need to initialize cli->nom to an address where it is guaranteed to be safe to write. You would do that in one of three ways, as I already listed for you:
    Originally Posted by DWise1
    1. You could malloc some memory to it that is enough to hold the longest possible name plus one more character for the null-terminator.

    2. Instead of declaring nom to be a char pointer, declare it to be a char array whose size is large enough to hold the longest possible name plus one more character for the null-terminator.

    or 3. Declare a local char array of sufficient size to serve as an input buffer to use with scanf("%s" . Then when you have input a name, use the function strdup to copy it to nom. strdup calls malloc to allocate enough memory to hold the string plus one for the null-terminator and then copies the string to that memory. Or instead of using strdup you could call malloc and strcpy yourself to do the same thing.
  2. #17
  3. No Profile Picture
    Contributing User
    Devshed Newbie (0 - 499 posts)

    Join Date
    Aug 2013
    Posts
    31
    Rep Power
    1
    Okay its way more clear now ! But I still got some questions:
    Where should I malloc the memory (in which block of the code) ? I can't initialize anything in the structures itselves, or should I make a init() function which allocates memory (malloc()) for each database[i] ? I tried and couldn't make it run...

    The array thing you said works, but it doesn't with age and gsm...
    Tried this : it crashes after asking for age...

    Code:
    #include <stdio.h>
    #include <stdlib.h>
    
    #define MAXNOM 20
    
    FILE * write;
    char * test;
    int l;
    int size;
    
    struct client
    {
    	char * nom;
    	int gsm;
    	int age;
    };
    
    struct client * database = NULL;
    
    void addclient( struct client * cli );
    void init();
    
    int main()
    {
    	int nbr = 0;
    	int n = 0;
    	int i;
    
    	typedef struct client Client;
    	printf("\nCombien de clients souhaitez vous ajouter dans votre BDD ?\n"); //how much clients in your database?
    	scanf("%d", &nbr);
    	size = nbr;
    	database = malloc(nbr*sizeof(Client));
            init();
    	
    	for(i = 0; i < nbr; i++)
    	{
    		addclient(&database[i]);
    	}
    	
    	printf("Quel client souhaitez vous consulter ?"); // which client's info do you want to see ?
    	scanf("%d", &n);
    	FILE * read;
    	read = fopen(database[n-1].nom, "r");
    	char * filecontent;
    	fgets(filecontent, 20, write);
    	printf("%s", filecontent);
    	
    	return 0;
    	
    }
    
    void addclient( struct client * cli )
    {
    	printf("\nNom du client : ");
    	scanf("%s", cli->nom);
    	write = fopen(cli->nom, "w");
    	printf("\nAge du client : ");
    	scanf("%d", cli->age);
    	printf("\nGSM du client : ");
    	scanf("%d", cli->gsm);
    	fprintf(write, "Nom : %s \nAge : %d \n GSM : %d \n",cli->nom, cli->age, cli->gsm);
    	fclose(write);
    }
    
    
    void init()
    {
    	for(l = 0; l < size ; l++)
    	{
    		database[l].nom = malloc(MAXNOM*sizeof(char));
    		database[l].age = 0;
    		database[l].gsm = 0;
    	}
    }
  4. #18
  5. Contributing User
    Devshed Supreme Being (6500+ posts)

    Join Date
    Jan 2003
    Location
    USA
    Posts
    7,145
    Rep Power
    2222
    Array of char has nothing to do with the age or gsm fields. Space is already allocated for them in the struct. All you need to do is give scanf the address of those fields. As you last had it written, you gave scanf the garbage integer values in those fields which scanf then tried to use as pointers, thus causing the same kind of crash you get when you use uninitialized pointers. Just give scanf of the address of the field.

    nom needs to be pointing to actual safe memory before you try to write any characters into it. If you are still going to scanf into nom, then you have to have either called malloc before scanf or you have to have changed nom to an array of char. If you choose the first option of malloc'ing to nom, then that could be in either function just so long as it's before you scanf into nom. If you are going to scanf into a buffer first and then copy that to nom, then simply declare a local char array in that function.

    Keep it simple and don't try to change a lot in a panic. Take a moment and think it through. If you understand what needs to be done, then figuring out how to do it becomes easier.
  6. #19
  7. Contributing User
    Devshed Supreme Being (6500+ posts)

    Join Date
    Jan 2003
    Location
    USA
    Posts
    7,145
    Rep Power
    2222
    Originally Posted by hooby.graphite
    The array thing you said works, but it doesn't with age and gsm...
    Tried this : it crashes after asking for age...
    You still are not giving scanf the addresses for age nor gsm! You are still getting warnings for those two lines of code! Correct the warnings!
  8. #20
  9. Contributing User
    Devshed Supreme Being (6500+ posts)

    Join Date
    Jan 2003
    Location
    USA
    Posts
    7,145
    Rep Power
    2222
    Code:
        database[l].nom = malloc(MAXNOM*sizeof(char));
    You must malloc MAXNOM plus one characters! Every C-style string has an extra character at the end, the null-terminator, which marks the end of the string. All functions that work with or use strings absolutely need that null-terminator! You must always allocate enough space to include the null-terminator. In order to accommodate a string that is MAXNOM characters in length, you must allocate (MAXNOM+1) characters.

    Never ever forget about the null-terminator! Doing so opens your program up to all kinds of really nasty bugs.

    PS
    I'll be out of reach for about four hours.
    Last edited by dwise1_aol; August 7th, 2013 at 08:00 PM.
  10. #21
  11. No Profile Picture
    Contributing User
    Devshed Newbie (0 - 499 posts)

    Join Date
    Aug 2013
    Posts
    31
    Rep Power
    1
    Sorry but I really don't see how I can do that... I corrected the MAXNOM to MAXNOM+1 but for age and gsm it still crashes.
    I tried to malloc(size of int) for each of them in a function that I call before the function addclient but it still crash..
    Really need some help and don't see how I can give the address of the int in the scanf.
  12. #22
  13. No Profile Picture
    Contributing User
    Devshed Newbie (0 - 499 posts)

    Join Date
    Jun 2013
    Posts
    40
    Rep Power
    19
    Code:
     	
    	printf("\nAge du client : "); 
    	scanf("%d", &cli->age);   /* scanf needs address */
    	printf("\nGSM du client : "); 
    	scanf("%d", &cli->gsm);  /* scanf needs address */
    ;)
  14. #23
  15. No Profile Picture
    Contributing User
    Devshed Newbie (0 - 499 posts)

    Join Date
    Aug 2013
    Posts
    31
    Rep Power
    1
    No Homi I still get warnings on those lines, saying it needs int * but receive int **.
    Program can write the file but can't read it.
    I did this to read it but it doesnt work :
    But at least it writes the file correctly like I wanted :)
    Update of the code:

    Code:
    #include <stdio.h>
    #include <stdlib.h>
    
    #define MAXNOM 20
    
    FILE * write;
    char * test;
    int l;
    int size;
    int readage;
    int readgsm;
    char * readname;
    
    struct client
    {
    	char * nom;
    	int * gsm;
    	int * age;
    };
    
    struct client * database = NULL;
    
    void addclient( struct client * cli );
    void init();
    
    int main()
    {
    	int nbr = 0;
    	int n = 0;
    	int i;
    
    	typedef struct client Client;
    	printf("\nCombien de clients souhaitez vous ajouter dans votre BDD ?\n"); //how much clients in your database?
    	scanf("%d", &nbr);
    	size = nbr;
    	database = malloc(nbr*sizeof(Client));
    	init();
    	for(i = 0; i < nbr; i++)
    	{
    	    printf("Client numero %d :\n", i);
    		addclient(&database[i]);
    	}
    	
    	printf("Quel id de client souhaitez vous consulter ?"); // which client's info do you want to see ?
    	scanf("%d", &n);
    	
    	FILE * read;
    	read = fopen(database[n-1].nom, "r");
    	fscanf(read, "Nom : %s\n Age : %d\nGSM : %d", readname, &readage, &readgsm);
    	printf("Nom : %s \nAge : %d \nGSM : %d",readname, readage, readgsm);
    	
    	return 0;
    	
    }
    
    void addclient( struct client * cli )
    {
    	printf("\nNom du client : ");
    	scanf("%s", cli->nom);
    	write = fopen(cli->nom, "w");
    	printf("\nAge du client : ");
    	scanf("%d", &cli->age);
    	printf("\nGSM du client : ");
    	scanf("%d", &cli->gsm);
    	printf("\n\n");
    	fprintf(write, "Nom : %s \nAge : %d \nGSM : %d",cli->nom, cli->age, cli->gsm);
    	fclose(write);
    }
    
    
    void init()
    {
    	for(l = 0; l < size ; l++)
    	{
    		database[l].nom = malloc((MAXNOM+1)*sizeof(char));
    		database[l].age = malloc(sizeof(int));
    		database[l].gsm = malloc(sizeof(int));
    	}
    }
  16. #24
  17. Contributing User
    Devshed Supreme Being (6500+ posts)

    Join Date
    Jan 2003
    Location
    USA
    Posts
    7,145
    Rep Power
    2222
    You're panicking. And because you're panicking, you're going stupid. Snap out of it! Calm down and re-engage your brain!

    You changed your struct:
    Code:
    struct client
    {
    	char * nom;
    	int * gsm;
    	int * age;
    };
    Why? It was correct to begin with. All you're doing here is to make everything more complicate, overly complicated. Don't do that! Follow the Golden Rule of Design and Planning: Keep It Simple, Stupid! (KISS)

    Change your struct back to what it was!

    You already know how to use scanf to read an integer value into an int variable. I know that because you already did it in your own code! So why are you suddenly going stupid on us? Here is what you did before:
    Code:
    	int nbr = 0;
    	int n = 0;
    	int i;
    
    	typedef struct client Client;
    	printf("\nCombien de clients souhaitez vous ajouter dans votre BDD ?\n"); //how much clients in your database?
    	scanf("%d", &nbr);
    Declaring and scanf'ing into age and gsm is no different than that. So why flying into a brain-dead panic over it? You already know what to do, so just do it!

    Another piece of advice for the present, the future, and the rest of your career and life: When you are troubleshooting a problem, make one and only one change at a time.

    And for learning to understand how to work with pointers (since, given your Java background, must be new to you), I will refer you to an excellent two-part article from an excellent magazine that is no longer in circulation: "Pointer Power in C and C++, Parts 1 and 2" by Christopher Skelly, The C Users Journal, Feb and Mar 1993. I found reprints of the articles at http://collaboration.cmc.ec.gc.ca/sc...lly/skelly.htm (Part 1) and at http://collaboration.cmc.ec.gc.ca/sc...lly/skelly.htm (Part 2). He based the articles on his ten years experience teaching the subject, plus he includes the game of Pointer Dominos that he had invented for his students to practice working with pointers.

    For example, if you had actually read the warnings that you reported to us -- "I still get warnings on those lines, saying it needs int * but receive int **." -- you would have seen that the problem being reported was differing levels of indirection and, had you stopped to think instead of panic, that would have told you how to correct that problem. Understanding and working with the concept of levels of indirection is very much a part of those two articles.

    Very smart of you to post the current state of your code. Far too many times all we are told is "I made some changes and it still doesn't work". Without seeing what they had changed the code to, we cannot possibly know what they did wrong. In this case, you did not tell us that you had changed the int fields in the struct to int pointers, but because you also posted the new code we were able to see that for ourselves and zero in on the problem. That is a good practice that I hope you will continue.
  18. #25
  19. No Profile Picture
    Contributing User
    Devshed Newbie (0 - 499 posts)

    Join Date
    Aug 2013
    Posts
    31
    Rep Power
    1
    Yeah sorry, I'm just panicking and being dumb all the time, it's because I started to program without having any idea of how I was going to do it and without having any organization, which is was I had very bad ideas of how to do the implementation. In the future I'll try to make a plan to how make the program with algorithm. It's because I only have been making tiny programs that don't need a lot of thinking about "how do I do it" before. :(

    What I did not understand BEFORE is that you say scanf need an address, so I thought since age and gsm are not pointers they have no valuable addresses too, which is why I thought about making them pointers and malloc() them, then I realized you only meant malloc() for the pointer variables, here, char * nom and not age and gsm (if I understood well) and that non-pointers don't need valuable addresses (no need for malloc() for age and gsm).

    So the changes I made again :
    changed the structure variable *age and *gsm to age and gsm
    changed the init() function, I do not malloc() for age and gsm, instead I just initialize them to zero (I think this is that way).
    Anyway the program worked with the *age and *gsm ones (for writing the file). I think the MAIN problem is for the reading part , that is from the fscanf(); through I made the fscanf() content look exactly the same than the file so I don't understand why it doesn't work...

    Thanks for your reading on pointers, I'm getting on it right now.

    The code right now :

    Code:
    #include <stdio.h>
    #include <stdlib.h>
    
    #define MAXNOM 20
    
    FILE * write;
    char * test;
    int l;
    int size;
    int readage;
    int readgsm;
    char * readname;
    
    struct client
    {
    	char * nom;
    	int gsm;
    	int age;
    };
    
    struct client * database = NULL;
    
    void addclient( struct client * cli );
    void init();
    
    int main()
    {
    	int nbr = 0;
    	int n = 0;
    	int i;
    
    	typedef struct client Client;
    	printf("\nCombien de clients souhaitez vous ajouter dans votre BDD ?\n"); //how much clients in your database?
    	scanf("%d", &nbr);
    	size = nbr;
    	database = malloc(nbr*sizeof(Client));
    	init();
    	for(i = 0; i < nbr; i++)
    	{
    	    printf("Client numero %d :\n", i);
    		addclient(&database[i]);
    	}
    
    	printf("Quel id de client souhaitez vous consulter ?"); // which client's info do you want to see ?
    	scanf("%d", &n);
    
    	FILE * read;
    	read = fopen(database[n-1].nom, "r");
    	fscanf(read, "Nom : %s\n Age : %d\nGSM : %d", readname, &readage, &readgsm);
    	printf("Nom : %s \nAge : %d \nGSM : %d",readname, readage, readgsm);
    
    	return 0;
    
    }
    
    void addclient( struct client * cli )
    {
    	printf("\nNom du client : ");
    	scanf("%s", cli->nom);
    	write = fopen(cli->nom, "w");
    	printf("\nAge du client : ");
    	scanf("%d", &cli->age);
    	printf("\nGSM du client : ");
    	scanf("%d", &cli->gsm);
    	printf("\n\n");
    	fprintf(write, "Nom : %s \nAge : %d \nGSM : %d",cli->nom, cli->age, cli->gsm);
    	fclose(write);
    }
    
    
    void init()
    {
    	for(l = 0; l < size ; l++)
    	{
    		database[l].nom = malloc((MAXNOM+1)*sizeof(char));
    		database[l].age = 0;
    		database[l].gsm = 0;
    	}
    }
    PS: Thanks a lot again for your support if I'm not abusing of it
  20. #26
  21. Contributing User
    Devshed Supreme Being (6500+ posts)

    Join Date
    Jan 2003
    Location
    USA
    Posts
    7,145
    Rep Power
    2222
    Code:
    char * readname;
    
    // . . . 
    
    	fscanf(read, "Nom : %s\n Age : %d\nGSM : %d", readname, &readage, &readgsm);
    	printf("Nom : %s \nAge : %d \nGSM : %d",readname, readage, readgsm);
    Where is the pointer readname initialized? Where is it pointing? Does that location belong to you? Is that location guaranteed to be safe to write to?

    You know what to do about this uninitialized pointer.

    Remember what I told you about uninitialized variables (which includes pointer variables) containing "random" garbage? Well, that only applies to local variables. Local variables are created on the stack (a working segment of memory that is used for function calls that is getting constantly reworked), they are not created until you call their function, they cease to exist when you exit the function, and they are not initialized automatically when they are created.

    OTOH, global variables (those declare outside of the functions, such as readname in your program) are created as the program is starting up and before main() is called and they exist until you terminate the program. Global variables are initialized when they are created: if you do not specify an initialization value, then they are initialized to zero.

    So then, readname, a global pointer, is initialized to zero, which in many systems is the NULL pointer. Does Address Zero (AKA 0x00000000, AKA 0000:0000 (in the 16-bit segmented memory model of the original IBM PC)) belong to your program? No, it does not; rather, it belongs to the operating system. What is at Address Zero? I'm fairly certain that Address Zero is where the Interrupt Vector Table lies, a table of addresses for the Interrupt Service Routines that must be called in response to interrupts so that the operating system and the computer itself can continue to function.

    When you attempt to write to readname, you are attempting to write to Address Zero, a location that not only does not belong to you, but is also vitally crucial to the operation of the computer. Needless to say, the operating system terminates your program with extreme prejudice.

    Do not attempt to write to Address Zero. Initialize your readname pointer to an address that both belongs to you and also is guaranteed to be a safe place to write to. You know how to do that.

    PS

    BTW, after having made that one correction:
    C:TEST>a

    Combien de clients souhaitez vous ajouter dans votre BDD ?
    1
    Client numero 0 :

    Nom du client : one

    Age du client : 42

    GSM du client : 345


    Quel id de client souhaitez vous consulter ?1
    Nom : one
    Age : 42
    GSM : 345
    C:TEST>
    Last edited by dwise1_aol; August 8th, 2013 at 11:52 AM.
  22. #27
  23. No Profile Picture
    Contributing User
    Devshed Newbie (0 - 499 posts)

    Join Date
    Aug 2013
    Posts
    31
    Rep Power
    1
    I had forgot that one, now I'll remember to malloc() for each pointer.
    My program works now. Thanks a lot for your support, you made me learn a lot of things. :)
    Now I'll try to program a little game in C with SDL or SFML
  24. #28
  25. No Profile Picture
    Contributing User
    Devshed Newbie (0 - 499 posts)

    Join Date
    Aug 2013
    Posts
    31
    Rep Power
    1
    Hello
    Sorry to disturb you but I really need huge help to set me up for libraries for SFML in C AND C++ and SDL for C.
    I did the tutorial of lazy foos (http://lazyfoo.net/SDL_tutorials/lesson01/windows/codeblocks/index.php) for installing SDL and the tutorial of SFML official website to install SFML (and I got exactly the same screenshots and read what they said (I made it dynamic, no static and I didn't put SFML_Static) and both crashes with the almost same error ! I use Code::blocks.
    I think it is because I installed multiple IDE before and that ****ed up all my compiler's installation... I wanted to know if there was nothing fully-made that I could just install and forget to make my program works with the library SFML ? (btw I plan to use CSFML, the C port of SFML).
    The errors:
    http://imgur.com/vD1w5uI
    and for SDL its the same message of error (couldn't find point of entry) but with one SDL library. For SFML, if I put all the libraries in the .exe directory, but then it asks for the mingw/bin libraries ?????????????? And if I put them, it opens a console then it crashes (even if I put in my project options that I wanted a GUI application).

    Do you recommend any simple solution because I really hate IDE, they are so ****ing hard to set up and if you do it wrong (did it wrong before since I installed multiple of them) they just **** up your computer so you can't install any more library with them.

    If you got a gcc tutorial for SFML (meaning what should I type to make a .exe) that would greatly help me, I find it easier to type gcc program.c -o program.exe and to link myself than to have to set up an IDE for hours. Unless you know a very good one (which I doubt) or have a ready-to-use package... :(

    Thanks a lot for your help and I wanted to thank you again for the program of database ! I know its not the good topic or forum but since you helped me nice on programming you must know maybe how to use libraries...

    Thanks in advance

    Comments on this post

    • dwise1_aol agrees : Sorry, not familiar with either library. I commiserate about setting them up, having been experienced that with Android development environments (never got it to work, just gave up).
  26. #29
  27. Contributing User
    Devshed Supreme Being (6500+ posts)

    Join Date
    Jan 2003
    Location
    USA
    Posts
    7,145
    Rep Power
    2222
    As I just said, I have no experience with either library. I recommend that you start a new topic with your questions.
Page 2 of 2 First 12
  • Jump to page:

IMN logo majestic logo threadwatch logo seochat tools logo