issues combining pointers\arrays\functions :(

This is a discussion on issues combining pointers\arrays\functions :( within the C Programming forums, part of the General Programming Boards category; Hi guys. I have an assignment and am having trouble making the functions, pointers, and character strings/arrays work together. I ...

  1. #1
    Registered User
    Join Date
    Oct 2012
    Location
    Sydney, Australia
    Posts
    13

    issues combining pointers\arrays\functions :(

    Hi guys. I have an assignment and am having trouble making the functions, pointers, and character strings/arrays work together.
    I have to use fgets() to take an input, then split it into the individual words/phrases that are typed and ignore excess spaces etc.

    for example, a valid input could be:
    i input.txt o output.txt p password k 2392
    but an equally valid input could be
    i input.txt o output.txt k 2392

    im getting a lot of errors that dislike me using char* when it wants normal char and vice versa. code is below. thanks!!!

    Code:
    --------main function -------------
    
    void main()
    {
        int x=0;
        int inp_out;
        char main_input[1000];
        char* string;
        char v1;
        char *value;
    
    
        printf("please enter files to be encrypted: ");
        
        fgets(main_input, sizeof(main_input), stdin);
    
    
        printf("\n\nmain_input = %s\n\n", main_input);
    
    
        get_next_value(*main_input);
    
    
        v1 = *value;
    
    
        get_next_value(*string);
    
    
        v2 = *value
    
            get_next_value(*string);
    
    
        v2 = *value
    
            get_next_value(*string);
    
    
        v2 = *value
    
    
    
    return 0;
    
    }
    
    ------- function get_next_input-----------
    
    char get_next_input(char s[])
    {
    
    
        char value;
        int i;
        int v =0;
        char* string;
    
    
        for(i=0;i<strlen(s);i++)
        {
            if(isalpha(s[i]))
            {
                value[v] = s[i];
                v++;             
                
                if(isspace(s[i+1]))
                {
                    string = &s[i+1];
                    
                    return value;
                }
            }
        }
    
    
    }

  2. #2
    Registered User
    Join Date
    Mar 2010
    Posts
    535
    Hmmm. Well, first step is to figure out what you actually want in each place. For instance, I'm guessing that get_next_value() is supposed to give you back a string (a word, in this case)?

    Strings can be char[] or char* depending on what you're doing with them, and "char" on its own is always just a single character. So:

    Code:
    char get_next_input(char s[])    // this takes an array s as a parameter and returns a single char
    Code:
        char value;
        ...
                value[v] = s[i];  // trying to treat the char as if it was a pointer or array. Not allowed
    It seems pretty obvious that these are the wrong types. You seem to know they're the wrong types.... so the answer really is to just use the right types! char* or char[] for strings, char for characters.


    You have scoping problems too -- e.g. you're updating the "string" variable in get_next_input and looks like you're expecting it to have been updated in main. It won't be -- the "string" in get_next_input is unrelated to the "string" in main. You need to have a think about how to share the variables between your functions.


    For now, I'd have to say that your code is so broken it's probably be best to take a step back and try to break the problem down. A good starting point might be to implement a function that reads a set number of characters from 1 string and returns them to the caller in another string. Worry about excess whitespace and chopping up the input string after you have something basic working, would be my advice.

  3. #3
    Registered User
    Join Date
    Oct 2012
    Location
    Sydney, Australia
    Posts
    13
    thanks for the update! yea i knew it was really broken.. just sort of gave up and asked for help in the middle of fixing it haha sorry!

    anyway i didn't realise that a normal char was only 1 character so that is really helpful thanks. when u say that it wont recognise 'string' in my main function, if string is a char* will it not recognise the address everywhere??? i thought with pointers that the address could be read from anywhere?? or do i have to initialise a variable first and then create a pointer to it? e.g. "int value = 5; int *v = &value"

    thanks for you're reply!

  4. #4
    Registered User
    Join Date
    Oct 2011
    Posts
    872
    Perhaps it would be simpler to have the get_next_value() read the value too? This one handles ASCII whitespace (as defined for the POSIX or C locale), and any newline encoding (and is thus best used for binary streams, "b" for fopen()):
    Code:
    /* Returns the length of the token if successful,
     * zero otherwise (end of line, or end of input).
    */
    size_t ftoken(char *const buffer, const size_t length, FILE *const in)
    {
        size_t  n = 0;
        int     c;
    
        c = getc(in);
    
        /* Skip leading whitespaces, but not newlines. */
        while (c == '\t' || c == '\v' || c == '\f' || c == ' ')
            c = getc(in);
    
        /* Scan token itself. */
        while (c != EOF && c != '\t' && c != '\n' && c != '\v' &&
               c != '\f' && c != '\r' && c != ' ') {
    
            /* Convert ASCII NULs to newlines. */
            if (c == '\0') {
                c = '\n';
                /* Since c is excluded in the loop condition, we need to break.
                 * If you used say ' ' instead of '\n', there would be
                 * no need to break here. */
                break;
            }
    
            if (n < length)
                buffer[n] = c;
    
            n++;
            c = getc(in);
        }
    
        /* Add terminating NUL. */
        if (n < length)
            buffer[n] = '\0';
        else
        if (length > 0)
            buffer[length - 1] = '\0';
    
        /* Keep newline character. */
        if (c == '\n' || c == '\r')
            ungetc(c, in);
    
        /* Return the length of the token. */
        return n;
    }
    
    /* Skip the rest of the line, to the next line. Returns EOF if end of file.
    */
    int fnextline(FILE *const in)
    {
        int c;
    
        c = getc(in);
    
        /* Skip to end */
        while (c != EOF && c != '\n' && c != '\r')
            c = getc(in);
    
        /* Consume the newline */
        if (c == '\r') {
            c = getc(in);
            if (c == '\n')
                c = getc(in);
    
        } else
        if (c == '\n') {
            c = getc(in);
            if (c == '\r')
                c = getc(in);
        }
    
        /* Un-consume the start of the next line. */
        if (c != EOF) {
            ungetc(c, in);
            return 0;
        } else
            return EOF;
    }
    The difference to your current code would be that you simply read tokens until ftoken() returns zero, or until you decide the rest of the line is not interesting. Then you call fnextline(), which will return EOF if there is no more lines, or 0 otherwise. For example:
    Code:
    int main(void)
    {
        char    buffer[100];
        size_t  length;
    
        while (1) {
    
            length = ftoken(buffer, sizeof buffer, stdin);
    
            if (length > 0) {
                printf("%lu chars, \"%s\"\n", (unsigned long)length, buffer);
    
            } else {
                /* length == 0: no token; end of line or file. */
    
                if (fnextline(stdin) == EOF)
                    break; /* out of the while loop */
    
                printf("New line\n");
            }
        }
    
        return 0;
    }
    Although reading the input one character at a time is somewhat slower than reading it line-by-line, this way you can easily support any newline encoding (text files travelled between Windows and Linux or Mac OS X systems). And, if you want, you can very easily add quoted string support, and quoted tokens that span multiple input lines. I did it just for testing; that ftoken() needed 79 lines of code not including blank lines and comments, but it also supported non-numeric escape sequences line \n. So it is certainly feasible.

  5. #5
    Registered User
    Join Date
    Oct 2012
    Location
    Sydney, Australia
    Posts
    13
    not quite understanding the code above put anyway here is where i am at:
    my main function below takes the user input 'main-input' using fgets and prints it. this works fine. i then have a pointer *ptr which points to the first element in the main_input array. this value is then sent to the function get_next_letter() which is meant to then return the first word in the array (and eventually every word). however it doesnt like me doing this as it says "argument of type char is incompatible with parameter char*" which i dont understand. then, the function should return 2 values. first of all "value" which is the first word it finds (ignoring all spaces) and secondly char* strptr which points to the first element in the array after the value.
    e.g. if i input "this phrase", value should = "this" and strptr should point to the space between the two words. however the program reads the main_input and then crashes
    any ideas why??? code is below
    Code:
    ----------------------main-------------------------
    #include <stdlib.h>
    #include <stdio.h>
    #include <ctype.h>
    #include <string.h>
    #include "declarations.h"
    
    
    void main()
    {
    	int x=0;
    	int inp_out;
    	char main_input[1000];
    	char *ptr = &main_input[0];
    	char string;
    	char v1;
    	char v2;
    	char value;
    	char strptr;
    
    
    	printf("please enter files to be encrypted: ");
    	
    	fgets(main_input, sizeof(main_input), stdin);
    
    
    	printf("\n\nmain_input = %s\n\n", main_input);
    
    
    	get_next_letter(*ptr);
    
    
    	printf("%d", value);
    	printf("%s", strptr);
    		
    }
    
    
    ------------------function------------------------
    char* get_next_letter(char *s)
    {
    
    
    	char value[50];
    	int i;
    	int v =0;
    	char* string[1000];
    	char* strptr =&value[1];
    
    
    	for(i=0;i<strlen(s);i++)
    	{
    		if(isalpha(s[i]))
    		{
    			value[v] = s[i];
    			v++;			 
    			
    			if(isspace(s[i+1]))
    			{
    				*strptr = s[i+1];
    				
    				return value;
    			}
    		}
    	}
    
    
    }

  6. #6
    Registered User
    Join Date
    Oct 2011
    Posts
    872
    Quote Originally Posted by jacka1993 View Post
    not quite understanding the code above
    Then you should save it into a file, compile and run it with some test input. Say you have file input.txt
    Code:
    One Two Three
      Foo    Bar Bazzz    
    Grabblebodyhgyrhf febbaghe
    compile the program, and run adding < input.txt to the command line.
    Then play with the code in the main(), until you understand what is happening.

    Quote Originally Posted by jacka1993 View Post
    my main function below takes the user input 'main-input' using fgets and prints it. this works fine. i then have a pointer *ptr which points to the first element in the main_input array. this value is then sent to the function get_next_letter() which is meant to then return the first word in the array (and eventually every word).
    Let's take a look at your get_next_letter() function, shall we?

    Quote Originally Posted by jacka1993 View Post
    Code:
    char* get_next_letter(char *s)
    {
    	char value[50];
    	int i;
    	int v =0;
    	char* string[1000];
    	char* strptr =&value[1];
    Okay, you have a local array of 49 characters plus end-of-string in value, 1000 pointers in string, and a pointer strptr pointing to the second character in value.
    Quote Originally Posted by jacka1993 View Post
    Code:
    	for(i=0;i<strlen(s);i++)
    	{
    Here you have a loop over each character position in s. That's okay, but you really should put the length in a temporary variable, say slen, so you won't recalculate the string length again and again.
    Quote Originally Posted by jacka1993 View Post
    Code:
    		if(isalpha(s[i]))
    		{
    			value[v] = s[i];
    			v++;			 
    			
    			if(isspace(s[i+1]))
    			{
    				*strptr = s[i+1];
    				
    				return value;
    			}
    		}
    	}
    No. Above, you copy the character to the value array; it will overflow when v reaches the size of the array, 50. (And the last entry, value[49] should contain the end-of-string '\0', not a character.)
    You then check if the following character is a white-space character, and if so, change the strptr pointer to that character value, and return the pointer to the local value array which will vanish when the function returns.

    So, I'm sorry, but there is not much in the function that works as you intended.

    If you just wanted the pointer to the start of the next token (word), and the whitespace or end-of-string following the current token you could use
    Code:
    char *starts(char *ptr)
    {
        while (isspace(*ptr))
            ptr++;
        return ptr;
    }
    
    char *ends(char *ptr)
    {
        while (*ptr != '\0' && !isspace(*ptr))
            ptr++;
        return ptr;
    }
    However, to "split" the token from the string, you need to place the end-of-string character, '\0'. That is what determines the end of the string. Without one, the string will just go on and on.

    Let's rewrite your main(), using the above two helper functions and the approach you descibed (but your code does not implement):
    Code:
    #include <stdio.h>
    #include <ctype.h>
    
    /* Skip to the next non-white-space character.
    */
    char *starts(char *ptr)
    {
        while (isspace(*ptr))
            ptr++;
        return ptr;
    }
    
    /* Skip to the next white-space character, or end-of-string mark.
    */
    char *ends(char *ptr)
    {
        while (*ptr != '\0' && !isspace(*ptr))
            ptr++;
        return ptr;
    }
    
    int main(void)
    {
        char  buffer[1024];
        char *left, *next;
        char  save;
    
        while (1) {
    
            /* Read new line into buffer. */
            left = fgets(buffer, sizeof buffer, stdin);
            if (!left) {
                /* No more data, or read error. Break out of while loop. */
                break;
            }
    
            /* Output the complete line. */
            printf("Line: \"%s\"\n", left);
    
            /* Find the start of the first token on line. */
            left = starts(left);
    
            /* No tokens? */
            if (*left == '\0')
                continue; /* Skip to reading the next line into buffer. */
    
            /* Output each token. */
            while (*left != '\0') {
    
                /* Where does this token end? */
                next = ends(left);
    
                /* Show what we have now: */
                printf("Have: \"%s\"\n", left);
    
                /* Show what is next. */
                printf("Next: \"%s\"\n", next);
    
                /* Save the end character, and put in an end-of-string. */
                save = *next;
                *next = '\0';
    
                /* We now have one token at left. */
                printf("TOKEN \"%s\"\n", left);
    
                /* Move to next token. */
                *next = save;
                left = starts(next);
            }
        }
    
        return 0;
    }

  7. #7
    Registered User
    Join Date
    Oct 2012
    Location
    Sydney, Australia
    Posts
    13
    thank you so much!! so much easier when you step me through it like that
    if i was to save each token into its own variable, is the best way to have an array of pointers e.g. array[5] for 5 pointers and then make the token variable = array[0] and then array[1] etc. as i loop through???? (or array[5][1024] or whatever it would be..

  8. #8
    Registered User
    Join Date
    Oct 2011
    Posts
    872
    Quote Originally Posted by jacka1993 View Post
    thank you so much!! so much easier when you step me through it like that
    You're welcome. Do not be discouraged about the errors; just try again. We all make a lot of errors.

    Also, I find it much easier to re-read my own code after a good night's sleep. Having a coding buddy, so you each check out the others code and point out any errors you find, is very useful too.
    Quote Originally Posted by jacka1993 View Post
    if i was to save each token into its own variable
    The tokens already exist in the line buffer -- until you read the next line, of course. So, it depends on whether you need the tokens to be available only until the next line is read, or for longer.

    If you only need them for the current line, then you only need an array of pointers. (They will, of course, point to the line buffer, at the start of each token.)

    Let's modify my example to do just that, shall we?
    Code:
    #include <stdio.h>
    #include <ctype.h>
    
    #define  MAX_LINE_LENGTH  1023
    #define  MAX_TOKENS  16
    
    /* Skip to the next non-white-space character.
    */
    char *starts(char *ptr)
    {
        while (isspace(*ptr))
            ptr++;
        return ptr;
    }
    
    /* Skip to the next white-space character, or end-of-string mark.
    */
    char *ends(char *ptr)
    {
        while (*ptr != '\0' && !isspace(*ptr))
            ptr++;
        return ptr;
    }
    
    int main(void)
    {
        char  buffer[MAX_LINE_LENGTH + 1];
        char *left, *next;
        char  save;
    
        char *token[MAX_TOKENS];
        int   tokens;
    
        int   i;
    
        while (1) {
    
            /* Lets clear the number of tokens on this line first. */
            tokens = 0;
    
            /* Read new line into buffer. */
            left = fgets(buffer, sizeof buffer, stdin);
            if (!left) {
                /* No more data, or read error. Break out of while loop. */
                break;
            }
    
            /* Output the complete line. */
            printf("Line: \"%s\"\n", left);
    
            /* Find the start of the first token on line. */
            left = starts(left);
    
            /* No tokens? */
            if (*left == '\0')
                continue; /* Skip to reading the next line into buffer. */
    
            /* Scan each token. */
            while (*left != '\0') {
    
                /* Where does this token end? */
                next = ends(left);
    
                /* Save the end character, and put in an end-of-string. */
                save = *next;
                *next = '\0';
    
                /* Save this token, if it fits in the array. */
                if (tokens < MAX_TOKENS)
                    token[tokens] = left;
    
                /* We have one more token. */
                tokens++;
    
                /* Was it a final token? */
                if (save == '\0')
                    break;
    
                /* The end-of-token '\0' replaced a blank,
                 * so we can skip it when scanning for the start
                 * of the next token. We must keep the '\0',
                 * as otherwise the token would not end. */
                left = starts(next + 1);
            }
    
            /* Were there too many tokens to fit in our buffer? */
            if (tokens > MAX_TOKENS) {
                fprintf(stderr, "Warning: Too many tokens (%d) in input line.\n", tokens);
    
                /* Limit tokens so we stay within our array. */
                tokens = MAX_TOKENS;
            }
    
            /* Print all the tokens. */
            for (i = 0; i < tokens; i++)
                printf("Token %d of %d is \"%s\"\n", i + 1, tokens, token[i]);
        }
    
        return 0;
    }
    Compare the two versions side-by-side. Can you see what I did to save the pointers to each token in the line buffer?

Popular pages Recent additions subscribe to a feed

Similar Threads

  1. Arrays, functions pointers
    By zmaker5 in forum C Programming
    Replies: 6
    Last Post: 07-23-2007, 02:47 PM
  2. Passing arrays of pointers into functions
    By ashley in forum C Programming
    Replies: 5
    Last Post: 01-13-2007, 06:48 PM
  3. Functions+Arrays+pointers
    By Cdrwolfe in forum C++ Programming
    Replies: 21
    Last Post: 07-06-2006, 12:33 PM
  4. passing arrays/pointers to functions
    By ygfperson in forum C++ Programming
    Replies: 5
    Last Post: 07-17-2002, 01:39 AM
  5. Pointers, arrays , functions
    By sballew in forum C Programming
    Replies: 19
    Last Post: 09-17-2001, 12:12 AM

Tags for this Thread


1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21