Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Reversing array in c - will not print -

The problem with this code is that it does not actually print anything after the user enters in some text in the command line.

The purpose of the code is to accept the number of lines the user will enter in via command prompt after the file name. Then the user will type something in to reverse. The program is supposed to reverse the user input for each line.

Example Input = the big red dog

Example Output = dog red big the

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <ctype.h>
#define SIZE 80

char * reverseWords(char *string);

//argc is the count of cmd arguments.
//each command line argument is of type string
int main(int argc, char *argv[]){

    //initialize local variables
    int i;
    int N;
    char str[SIZE];

    for(i = 1; i <argc; i++)
    {
        //set N equal to the users number in the command line 
        N = atoi(argv[i]);
    }

    if(argc != 2){//2 means that something is in the argument.
        printf("ERROR: Please provide an integer greater than or equal to 0");
        exit(1);//exit the program
    }else if(N < 0){//We cant have a negative array size.
        printf("ERROR: Please provide an integer greater than or equal to 0");
        exit(1);//exit the program
    }else{
        for(i = 0; i < N; i++){
            /*
            fgets(pointer to array, max # of chars copied,stdin = input from keyboard) 
            */
            fgets(str,SIZE,stdin);

            printf("%s", reverseWords(str)); //<---does not print anything....
        }           
    }
    return 0;
}   


char * reverseWords(char *line){

    //declare local strings 
    char *temp, *word;
    //instantiate index
    int index = 0;
    int word_len = 0;
    /*set index = to size of user input
        do this by checking if the index of line is
        equal to the null-character.
    */
    for(int i = 0; line[i] != '\0';i++)
    {
        index = i;//index = string length of line.
    }

    //check if index is less than 0.
    //if not we decrement the index value.

    for(index; index != -1; index--){
        //checking for individual words or letters
        if(line[index] == ' ' && word_len > 0){
            strncpy(word,line,word_len);
            strcat(temp , (word + ' '));
            word_len = 0;

        }else if(isalnum(line[index])){
            word_len == word_len+1;
        }//end if

    }//end loop

    //copy over the last word after the loop(if any)
    if(word_len > 0){
        strncpy(word,line,word_len);
        strcat(temp,word);
    }//end if
    line = temp;
    return line;
}//end procedure 
like image 753
pewpew Avatar asked Apr 07 '17 00:04

pewpew


1 Answers

It should come without surprise that reverseWords prints nothing. Why?

char * reverseWords(char *line){
    ...
    char *temp, *word;
    ...
    line = temp;
    return line;
} //end procedure

Where is line pointing? (to temp). Where was temp declared? (in reverseWords). How much storage was allocated to temp (none -- it is an uninitialized pointer)

Further, what happens to the memory associated with the function reverseWords when it returns? (it's destroyed...), so even if you had done something like char temp[strlen(line)+1] = "";, reverseWords would venture off into Undefined Behavior because the pointer you return, points somewhere within the reverseWords stack frame that was destroyed when reverseWords returned...

How do you fix this? You have three options, (1) pass a second pointer to a second array with sufficient storage, e.g.:

char *revwords (char *rline, char *line)

or, (2) dynamically allocate storage for temp so that the memory associated with temp survives the return of reverseWords, or

(3) use an adequately sized array for temp in reverseWords and overwrite line with the data in temp before the return. (e.g. use strcpy instead of the assignment line = temp;)

While dynamic allocation is straight forward, and creating a separate array in reverseWords is fine, you are probably better passing a second sufficiently sized array as a parameter to reverseWords.

It is completely unclear what you are doing with the argc and argv arguments in your code, the arguments to main have been omitted from the example below. The following is a short example of reversing the words in each line read from stdin,

#include <stdio.h>
#include <string.h>

#define SIZE 256

char *revwords (char *rline, char *line);

int main (void) {

    char line[SIZE] = "", rline[SIZE] = ""; /* storage for line/rline */

    while (fgets (line, SIZE, stdin)) { /* for each line on stdin */
        printf ("\n line: %s\nrline: %s\n", line, revwords (rline, line));
        *rline = 0; /* set first char in rline to nul-byte */
    }

    return 0;
}

char *revwords (char *rline, char *line)
{
    size_t lnlen = strlen (line);   /* length of line */
    /* pointer, end-pointer, rev-pointer and flag pointer-to-space */
    char *p = line + lnlen - 1, *ep = p, *rp = rline, *p2space = NULL;

    if (!line || !*line) {  /* validate line not NULL and not empty */
        fprintf (stderr, "revwords() error: 'line' empty of null.\n");
        return NULL;
    }

    if (*ep == '\n')    /* if line ends in '\n' -- remove it */
        *ep-- = 0;
    else                /* warn if no '\n' present in line */
        fprintf (stderr, "warning: no POSIX '\\n' found in line.\n");

    for (; ep >= line; ep--) {  /* for each char from end-to-beginning */
        if (*ep == ' ') {               /* is it a space? */
            size_t len = p - ep;        /* get the length of the word */
            strncat (rp, ep + 1, len);  /* concatenate word to rline  */
            if (p == line + lnlen - 1)  /* if first word, append ' '  */
                strcat (rp, " ");
            p = ep;                     /* update p to last ' '  */
            p2space = ep;               /* set flag to valid pointer */
        }
    }
    strncat (rp, line, p - line);       /* handle first/last word */

    if (!p2space) { /* validate line contained ' ', if not return NULL */
        fprintf (stderr, "revwords() error: nothing to reverse.\n");
        return NULL;
    }

    return rline;   /* return pointer to reversed line */
}

Note: if there is no '\n' present in line when passed to revwords, you are likely trying to read a line longer than SIZE chars (or you are reading the last line where there is no POSIX '\n' at the end of the file), and you need to handle that as required. Here I simply warn.

Example Use/Output

$ printf "my dog has fleas\nmy cat does too\n" | ./bin/str_rev_words

 line: my dog has fleas
rline: fleas has dog my

 line: my cat does too
rline: too does cat my

Look things over and let me know if you have any questions. There are dozens of ways to approach this problem, no one more right than another if they properly handle the reversal in a reasonable efficient manner. Take your pick.

If you like using the string library functions instead of pointer arithmetic, you could always do something like the following:

char *revwords (char *rline, char *line)
{
    /* length, pointer, end-pointer, pointer-to-space, copy of line */
    size_t len = strlen (line);
    char *p = NULL, *p2space = NULL, copy[len+1];

    if (!line || !*line) {  /* validate line not NULL and not empty */
        fprintf (stderr, "revwords() error: 'line' empty of null.\n");
        return NULL;
    }

    if (line[len-1] == '\n')    /* remove trailing newline */
        line[--len] = 0;
    else                /* warn if no '\n' present in line */
        fprintf (stderr, "warning: no POSIX '\\n' found in line.\n");

    strncpy (copy, line, len + 1);  /* copy line to 'copy' */

    /* for each ' ' from end-to-beginning */
    while ((p = strrchr (copy, ' '))) {
        strcat (rline, p + 1);          /* append word to rline */
        strcat (rline, " ");            /* followed by a space  */
        p2space = p;                    /* set p2space to p     */
        *p2space = 0;                   /* nul-terminate copy at p */
    }

    if (p2space) {              /* validate space found in line */
        *p2space = 0;           /* nul-terminate at space       */
        strcat (rline, copy);   /* concatenate first/last word  */
    }
    else {                      /* no ' ' in line, return NULL  */
        fprintf (stderr, "revwords() error: nothing to reverse.\n");
        return NULL;
    }

    return rline;   /* return pointer to reversed line */
}

Note: While not an error, the standard coding style for C avoids the use of caMelCase or MixedCase variable or funciton names in favor of all lower-case while reserving upper-case names for use with macros and constants. Leave caMelCase or MixedCase for java or C++. (it's style, so it's your choice, but it does say something about your code on first impression)

like image 137
David C. Rankin Avatar answered Oct 18 '22 08:10

David C. Rankin