1

I have created the two following functions. The first, eatWrd, returns the first word in a string without any white spaces, and removes the first word from the input string:

MAX is a number representing the max length of a string

char* eatWrd(char * cmd)
{
  int i = 0;        //i will hold my place in cmd
  int count = 0;    //count will hold the position of the second word
  int fw = 0;       //fw will hold the position of the first word
  char rest[MAX]; // rest will hold cmd without the first word
  char word[MAX]; // word will hold the first word

  // start by removing initial white spaces
  while(cmd[i] == ' ' || cmd[i] == '\t'){
    i++;
    count++;
    fw++;
  }

  // now start reading the first word until white spaces or terminating characters
  while(cmd[i] != ' ' && cmd[i] != '\t' && cmd[i] != '\n' && cmd[i] != '\0'){
    word[i-fw] = cmd[i];
    i++;
    count++;
  }
  word[i-fw] = '\0';

  // now continue past white spaces after the first word
  while(cmd[i] == ' ' || cmd[i] == '\t'){
    i++;
    count++;
  }

  // finally save the rest of cmd
  while(cmd[i] != '\n' && cmd[i] != '\0'){
    rest[i-count] = cmd[i];
    i++;
  }
  rest[i-count] = '\0';

  // reset cmd, and copy rest back into it
  memset(cmd, 0, MAX);
  strcpy(cmd, rest);

  // return word as a char *
  char *ret = word;
  return ret;
}

The second, frstWrd, just returns the first word without modifying the input string:

// this function is very similar to the first without modifying cmd
char* frstWrd(char * cmd)
{
  int i = 0;
  int fw = 0;
  char word[MAX];

  while(cmd[i] == ' ' || cmd[i] == '\t'){
    i++;
    fw++;
  }

  while(cmd[i] != ' ' && cmd[i] != '\t' && cmd[i] != '\n' && cmd[i] != '\0'){
    word[i-fw] = cmd[i];
    i++;
  }
  word[i-fw] = '\0';

  char *ret = word;
  return ret;
}

To test the function, I used fgets to read a string from the User(me), and then I printed three strings (frstWrd(input), eatWrd(input), eatWrd(input)). I would have expected that given a string, "my name is tim" for example, the program would print "my my name", but instead it prints the third word three times over, "is is is":

// now simply test the functions
main()
{
  char input[MAX];
  fgets(input, MAX - 1, stdin);
  printf("%s %s %s", frstWrd(input), eatWrd(input), eatWrd(input));
}

I have looked over my functions over and over and cannot see the mistake. I believe there is simply something I don't know about printf, or about using multiple string modification functions as arguments in another function. Any insight would be helpful thanks.

quigs
  • 23
  • 5
  • Jut one long paragraph describing your problem is hard to read. Try to split up the information somehow. – bolov Feb 01 '15 at 20:55
  • 2
    Related: You should wonder whether there are any guarantees as to the order of execution of those three function calls in your `printf()` arguments. (spoiler: there is no such guarantee). And there is clearly *undefined behavior* in your return values (see Volands answer below). – WhozCraig Feb 01 '15 at 20:58
  • ty, I personally think it's much better now. – bolov Feb 01 '15 at 21:10
  • duplicate, http://stackoverflow.com/questions/25798977/returning-string-from-c-function (and a dozen other threads) – M.M Feb 01 '15 at 22:51

1 Answers1

1

As I see rest and word are local variables in the function eatWrd. So it is bad practice to return pointer to such memory outside functions.

EDIT 1:

Also you should understand, that in line

printf("%s %s %s", frstWrd(input), eatWrd(input), eatWrd(input));

function eatWrd(input) could be called the first (before frstWrd(input)).

EDIT 2:

This can be usefull in finction eatWrd

  //char rest[MAX]; // rest will hold cmd without the first word
  char * rest = (char*) malloc(MAX);

And new main let be as:

int main()
{
  char input[MAX];
  fgets(input, MAX - 1, stdin);
  printf("%s ", frstWrd(input));
  printf("%s ", eatWrd(input));
  printf("%s\n", eatWrd(input));
}

And in the end my solution for frstWrd (just to show how standard functions can be useful):

char* frstWrd(char * cmd)
{
  char * word = (char *) malloc(MAX);
  sscanf(cmd, "%s", word);
  return word;
}
VolAnd
  • 6,367
  • 3
  • 25
  • 43
  • Ok thanks, so is there any good way to return a string from a c function? – quigs Feb 01 '15 at 21:15
  • @quigs You can also just `malloc()` the memory you need for the string and return that. The big advantage of this approach is that you don't need to use a preallocated buffer with a given size, instead you call allocate your memory to fit the string. This eliminates a huge error source. This is even more convenient, as there are already some standard functions (POSIX-2008 standard) that return malloc'ed strings (`asprintf()`, `strdup()`, etc.). These can usually be used to do the heavy lifting. The only thing you need to remember is the `free()` call. – cmaster - reinstate monica Feb 01 '15 at 21:23
  • @quigs: Functions of type char* return pointers, and very importnt to use memory that is available after function is finished. So there are three options: a) use memory from heap (allocate with malloc or similar functions); b) use static local variables (memory will be reserved and available between function is working); c) return pointers to memory that occupied by global variables or memory allocated outside (e.g. memory pointed by cmd in your example). – VolAnd Feb 01 '15 at 21:25