Pointers to Structs feilds.

Discussion in 'Mac Programming' started by larswik, Jan 6, 2011.

  1. larswik macrumors 68000

    Joined:
    Sep 8, 2006
    #1
    It says That I am getting a syntax error and I can't see what it is? I am deviating from the book with some tests to make sure I understand this before I move on. I am trying to pass a struct pointer as a parameter to my function .Then try to populate the char array 'words' in the struct with the char string 'Hello'.Then back in main I am trying to write the word out to the console. (I wrote out what I was trying to do so I could also see if my grammar was correct in stead of just saying I was getting a syntax error). The only thing I just thought of before I post this message is that I might need to populate the char with a for loop 1 letter at a time?

    Header file
    Code:
    #define kMaxList 50
    #define kMaxNumber 10
    
    struct larsList 
    {
    	char words[kMaxList];
    	char list[kMaxNumber];
    };
    
    main.c
    Code:
    #include <stdio.h>
    #include <stdlib.h>
    #include <string.h>
    #include "dvdTest.h"
    
    void printStuff(struct larsList *myList);
    
    int main (int argc, const char * argv[]) {
    		
    	struct larsList myList;
    	
    	printStuff(&myList);
    	printf("The word is: %s", myList.words);
    
    	
        return 0;
    }
    void printStuff(struct larsList *myList) 
    {
    	myList->words[kMaxList] = {'H','e','l','l','o','\0'};
    }
    	
    	
    
     
  2. mfram macrumors 65816

    Joined:
    Jan 23, 2010
    Location:
    San Diego, CA USA
    #2
    You can only use that type of construct in an initializer when declaring the variable.

    Try:

    Code:
    strcpy(mylist->words, "Hello");
     
  3. larswik thread starter macrumors 68000

    Joined:
    Sep 8, 2006
    #3
    Wow that was a fast reply :) I have not learned strcpy yet in the book. That would explain why It is not working if I can only do that when I declare the char array.

    Thanks!
     
  4. z0rt macrumors newbie

    Joined:
    Jan 3, 2011
    #4
    Instead of using the built-in function strcpy, you might want to write your own. Don't limit yourself only to for loops--experiment a little with while and do-while.
     
  5. mfram macrumors 65816

    Joined:
    Jan 23, 2010
    Location:
    San Diego, CA USA
    #5
    Oh, no strcpy() yet. Then write one. :)

    Code:
    char  *h = "Hello";  
    char *d = myList->words;
    while (*d++ = *h++);
    Extra credit for explaining how this works.
     
  6. larswik thread starter macrumors 68000

    Joined:
    Sep 8, 2006
    #6
    haha... Ya that is a little above what I know so far, but you gave me an idea and this ended up working. I think I am going to miss the extra credit on that one :)

    Code:
    }
    void printStuff(struct larsList *myList) 
    {
    	char theWord[6] = {'H','e','l','l','o','\0'};
    	int i;
    	
    	for(i = 0; i <= 6; i++){
    		myList->words[i] = theWord[i];
    	}
    
    }
     
  7. dmi macrumors regular

    Joined:
    Dec 21, 2010
    #7
    Code:
    void printStuff(struct larsList *myList)
    {
      // you could do                                                                                       
      struct larsList stuff={{'H','e','l','l','o','\0'},{'\0'}};
     *myList=stuff;
     // but you can't do   myList->words = stuff.words;
    
     // you can do                                                                                        
     myList->words[0] = stuff.words[0];
     // but you can't do   myList->words[kMaxList] = stuff.words[kMaxList]; (Do you see why not?)                                                     
    }
    
     
  8. dmi macrumors regular

    Joined:
    Dec 21, 2010
    #8
    By the way,
    One disadvantage of
    Code:
    struct larsList myStuff[1]={{{"Hello"},{"world"}}};
    char *h = myStuff->words
    char *d = myList->words;
    while (*d++ = *h++);
    
    compared to
    Code:
    char  *h = "Hello";  
    char *d = myList->words;
    while (*d++ = *h++);
    is that
    Code:
    char  *h = "Hello";
    doesn't waste as much space.

    One advantage of
    Code:
    struct larsList myStuff={...}
    is that
    Code:
    #define kMaxList 50
    #define kMaxNumber 10
    
    struct larsList
    {
      char words[kMaxList];
      char list[kMaxNumber];
    };
    struct larsList myStuff={{"hello"},{"world without end"}};
    char *h = myStuff.list;
    char *d = myList->list;
    while (*d++ = *h++);
    
    generates a compile time error rather than run time error.
     
  9. jared_kipe macrumors 68030

    jared_kipe

    Joined:
    Dec 8, 2003
    Location:
    Seattle
    #9
    Careful with the <=6 there. You are overrunning that array.
    'H' == theWord[0];
    '\0' == theWord[5];
    theWord[6] == probably the first byte of int i;
     
  10. larswik thread starter macrumors 68000

    Joined:
    Sep 8, 2006
    #10
    That is the thing that screws me up sometimes. I count 'Hello' on my fingers and I come up with a 5 char array for that word. I then think I need the 6th char to be the zero terminator so 'char theWord[6]' to me works?

    char theWord[6] is it '0-6' chars, or '0-5' chars?

    So 'char theWord[6]' says I want 6 char variables but 'theWord[4]' means I am working with char number [4]?

    -Lars
     
  11. lee1210 macrumors 68040

    lee1210

    Joined:
    Jan 10, 2005
    Location:
    Dallas, TX
    #11
    When declaring an array, you give the number of elements you want available. When using an index into an array the valid values start at 0 and go to n-1 where n is the length of the array. So:
    Code:
    char theWord[6];
    ...
    theWord[0] ='H';
    theWord[1] ='e';
    theWord[2] ='l';
    theWord[3] ='l';
    theWord[4] ='o';
    theWord[5] ='\0';
    
    theWord[6] would be past the end of the array, hence an overflow, meaning if you stored something there you would be overwriting something else inadvertently. This could cause no harm, or could cause your program to die a fiery death at some seemingly unrelated line.

    -Lee
     
  12. jiminaus macrumors 65816

    jiminaus

    Joined:
    Dec 16, 2010
    Location:
    Sydney
    #12
    When counting lengths of an array this works. When counting positions in an array, this doesn't work. For positions, the first count needs to be a closed fist which represents position zero, then the second count is the first finger or thumb, and so on.

    0-5 chars

    Yes

    This is one of the many reasons C is not taught as a first language by people who actually teach programming. Few other languages are as dangerous as to silently let you corrupt other memory by accessing an array past it's end. As a beginner, you can't be expected to be on the look out of these kinds of bugs. It's even hard for experienced C programmers to diagnose this kind of bug, who's symptom is a program crash far from the bug.

    Beginners make mistakes. So they need a language that saves them from themselves. C is the complete opposite. C assumes you know what you're doing; which is why experienced programmers love it so much.

    This is not discourage you at all Lars. It's just to point out that these mistakes are completely normal, and that part of the blame is on C. ;)
     
  13. larswik thread starter macrumors 68000

    Joined:
    Sep 8, 2006
    #13
    Thanks! I reread Jared post and understand my error with the '<=6'. I just took the [6] from theWord and used it for my counter not remembering that it only went to 5. For that to work I should have written it like this '<=5' or '<6'

    Thank you.

    -Lars
     
  14. dmi macrumors regular

    Joined:
    Dec 21, 2010
    #14
    One way to avoid having to count on your fingers is to let the compiler do it for you:
    Code:
    char theWord[] = {'H','e','l','l','o','\0'};
    // which can also be written char theWord[] = {"Hello"};
    	int i;	
    	for(i = 0; i < (sizeof(theWord)/sizeof(theWorld[0])); i++){
    		myList->words[i] = theWord[i];
    	}
    }
     
  15. larswik thread starter macrumors 68000

    Joined:
    Sep 8, 2006
    #15
    That is a nice tip, thanks DMI. This will help me to count when I run out of fingers :)

    -Lars
     
  16. lee1210, Jan 8, 2011
    Last edited: Jan 8, 2011

    lee1210 macrumors 68040

    lee1210

    Joined:
    Jan 10, 2005
    Location:
    Dallas, TX
    #16
    A few suggestions:
    echo "my great string that is too long to eyeball its length" | wc
    Edit: you still need to add 1 for the null terminator.

    However, if you just need a fixed string you don't need an explicit array at all:
    Code:
    const char *myString = "This is my string";
    
    -Lee
     
  17. dmi macrumors regular

    Joined:
    Dec 21, 2010
    #17
    A beginner may be tempted to think being able to do
    Code:
            char theWord[] = {"Hello"};
    	for(i = 0; i < (sizeof(theWord)/sizeof(theWorld[0])); i++){
    
    might mean that you could also do
    Code:
            char *theWord = "Hello";
    	for(i = 0; i < (sizeof(theWord)/sizeof(theWorld[0])); i++){
    
    But the latter would not work, because sizeof(theWord) would be the size of the pointer, not the size of the array.
    However, since "" strings are null terminated, you may not need a count, and can loop until the null:
    Code:
    	for(i = 0; theWord[i]; i++){
    
    but if you are copying a string, you may need to be sure to write the loop such that the null is also copied, e.g.
    Code:
    	for(i = 0; myList->words[i] = theWord[i]; i++);
    
     
  18. larswik thread starter macrumors 68000

    Joined:
    Sep 8, 2006
    #18
    That brings up another question that I am a little unsure off, where to put the zero-terminator.

    Example, lets say I create a 500 char array and only put the word hello in there.

    theWord[500]= {"Hello"};
    theWord[499] = '\0';

    This will leave a lot of empty chars but still it has the Zero-terminator so it seems fine to me even though there is a lot of empty space. Now lets say later in the code I write this...

    theWord[0] = {'W'};
    theWord[1] = {'0'};
    theWord[2] = {'r'};
    theWord[3] = {'l'};
    theWord[4] = {'d'};
    theWord[5] = {'\0'};

    It will replace the word 'Hello' and add a zero terminator to theWord[5] but also I have a zero terminator at theWord[499], is this OK or should I not zero terminate theWord[5] since theWord[499] already is already terminated for that char array?

    -Lars
     
  19. jiminaus macrumors 65816

    jiminaus

    Joined:
    Dec 16, 2010
    Location:
    Sydney
    #19
    The zero-terminator should go after the last character in the string. This may or may not be the last character in the array.

    The zero-terminator marks where in the array is the end of the string. All the positions in the array after the zero-terminator are not considered to be part of the string. If there happens to be multiple zero-terminators, then only the first one is significant.

    So to further refine your C knowledge. A string is a sequence of characters followed immediately by a zero-terminator. A character array is not a string. A character array is just a sequence of characters. A character array can contain a string.

    BTW You don't need to explicitly add a zero-terminator like you did in this code:

    Code:
    char theWord[500]= {"Hello"};
    theWord[499] = '\0';
    
    (I added the char, otherwise the code is outright wrong). Because a string literal automatically includes a zero-terminator. The code above is equivalent to the code below.

    Code:
    char theWord[500] = { 'H', 'e', 'l', 'l', 'o', '\0' };
    theWord[499] = '\0';
    
    Furthermore, the zero-terminator at position 499 is redundant/wrong because it's not immediately after the last character in the string.
     
  20. larswik thread starter macrumors 68000

    Joined:
    Sep 8, 2006
    #20
    I see. My worry was when the program is running if I said char theWord[500] it then blocks off a piece of memory for that array so the program can't accidentally write to that array block of memory and crash the program. I was unsure if I did not have a Zero Terminator at the end of the array, if the computer would see that as available memory if I had the zero terminator at theWord[5] = '\0'; instead of [499] to mark the end of that array.

    But from what you said I guess once it initializes the char theWord[500] array the computer already knows not to write anything in to that array even if I set the zero terminator at theWord[5].

    Thanks!

    -Lars
     
  21. jiminaus macrumors 65816

    jiminaus

    Joined:
    Dec 16, 2010
    Location:
    Sydney
    #21
    Yup, you're right. The char theWord[500] reserves enough memory to store 500 characters, and that memory won't be used for anything else. (Speaking loosely).
     
  22. larswik thread starter macrumors 68000

    Joined:
    Sep 8, 2006
    #22
    In my learning... I am trying to create a Header file for my struct and a Function Prototype for passing a struct as the parameter.

    Then fill in a word at scanf to be placed in to the myArray[4].rating field. Using the Function I want to send myArray[5].rating as the parameter and have it duplicate myArray[4].rating to myArray[5].rating. Then back in Main print out the result. I am not getting an error message but warnings so I know I am close.

    Header File
    Code:
    #define kRatingTotal 10
    #define kComment 256
    
    struct testArray {
    	char rating[kRatingTotal];
    	char comment[kComment];
    };
    
    
    void passArray(struct testArray myArray[4]);
    
    Main.C
    Code:
    #include <stdio.h>
    #include <string.h>
    #include "struct_test.h"
    
    
    int main (int argc, const char * argv[]) {
    	
    	struct testArray myArray[50];
    	
    	int theSize, theLen;
    	
    	printf("What is the rating:");
    	scanf("%s", &myArray[4].rating);
    	
    	
    	theSize = sizeof(myArray[4].rating);
    	theLen = strlen(myArray[4].rating);
    	
    	
    	printf("The Size is %d\n", theSize);
    	printf("The len of the string is is %d\n", theLen);
    	
    	passArray(myArray[5].rating);
    	
    	printf("myArray 5 says: %s ", myArray[5].rating);
    	
        return 0;
    }
    void passArray(struct testArray myArray[4]) {
    	
    	*myArray[5].rating = myArray[4].rating;
    }
    
     
  23. dmi macrumors regular

    Joined:
    Dec 21, 2010
    #23
    Code:
      passArray(myArray);
    }
    
    void passArray(struct testArray myArray[50]) {
      strcpy(myArray[5].rating,myArray[4].rating);
    }
    
    
     
  24. dmi macrumors regular

    Joined:
    Dec 21, 2010
    #24
    Code:
    void passArray(struct testArray myArray[50]) {
       myArray[5] = myArray[4]; // also works, but it may not be advisable for a beginner to consider such things
    }
    
     
  25. jiminaus macrumors 65816

    jiminaus

    Joined:
    Dec 16, 2010
    Location:
    Sydney
    #25
    This won't quite work. Because a copy of the array is passed into passArray, the changes within passArray won't be visible to main. You would need this:

    Code:
        passArray(myArray);
        /* ... */
    }
    
    void passArray(struct testArray * myArray) {
        strcpy(myArray[5].rating, myArray[4].rating);
    }
    
     

Share This Page