Reversing words within a string

青春壹個敷衍的年華 提交于 2021-02-11 15:33:07

问题


I am to reverse the words within a string. I feel like I'm headed in the right direction. But I keep getting wonky output and cant help but think it has to do with my strncat() function. Do any of you see any issues with out I've decided to handle it. I'm open to suggestion on other ways to do it.

int main()
{
  int ch, ss=0, s=0;
  char x[3];
  char *word, string1[100], string2[100], temp[100];
  x[0]='y';

  while(x[0]=='y'||x[0]=='Y')
  {
    printf("Enter a String: ");
    fgets(string1, 100, stdin);
    if (string1[98] != '\n' && string1[99] == '\0') { while ( (ch = fgetc(stdin)) != EOF && ch != '\n'); }

    word = strtok(string1, " ");

    while(word != NULL)
    {
      s = strlen(word);
      ss=ss+s;

      strncpy(string2, word, s);
      strncat(string2, temp, ss);
      strncpy(temp, string2, ss);

      printf("string2: %s\n",string2);
      printf("temp: %s\n",temp);      
      word = strtok(NULL, " ");
    }

    printf("Run Again?(y/n):");
    fgets(x, 2, stdin);
    while ( (ch = fgetc(stdin)) != EOF && ch != '\n');
  }

  return 0;
}

This is my output:

Enter a String: AAA BBB CCC DDD EEE

string2: AAA
temp: AAA

string2: BBBAAA
temp: BBBAAA

string2: CCCAAABBBAAA
temp: CCCAAABBB

string2: DDDAAABBBAAACCCAAABBB
temp: DDDAAABBBAAA

string2: EEE
AABBBAAACCCAAABBBDDDAAABBBAAA
temp: EEE
AABBBAAACCCA

回答1:


You need to initialize "at least" the first byte of strcat() parameters, because it expects it's parameters to be nul terminated, so

string2[0] = '\0';

would help, but you don't need strcat() for the first time, you can use strcpy() instead.




回答2:


You're not copying enough characters in your strncpy calls.

From the man pages:

The strncpy() function is similar, except that not more than n bytes of src are copied. Thus, if there is no null byte among the first n bytes of src, the result will not be null-terminated.

Since you're specifying the exact length of the string, no NULL terminating byte is appended.

You need to add 1 to each of these:

  strncpy(string2, word, s+1);
  strncat(string2, temp, ss);   // strncat always NULL terminates
  strncpy(temp, string2, ss+1);

Output:

Enter a String: aaa bbb ccc ddd eee

string2: aaa
temp: aaa
string2: bbbaaa
temp: bbbaaa
string2: cccbbbaaa
temp: cccbbbaaa
string2: dddcccbbbaaa
temp: dddcccbbbaaa
string2: eee
dddcccbbbaaa
temp: eee
dddcccbbbaaa

The split line on the last iteration is because fgets leaves the newline at the end of the buffer. You can skip over it by including \n in the delimiter list to strtok:

word = strtok(string1, " \n");
...
word = strtok(NULL, " \n");



回答3:


It is rather difficult to determine whether you are actually attempting to:

reverse the words within a string

or reverse the string.

If you are simply trying to reverse the whole string, then it wouldn't make much sense to separate the string into tokens when all you would need to do is write the original in reverse order.

Taking your request at face value, it may be easier to simply walk down the string with a start-pointer 'p' and end-pointer 'ep' and reverse what is between the two pointers when you find a space with 'ep'. In other words step down the new copy of the original string and with 'p' pointing to the beginning of each word and when 'ep' points to the space at the end of that word (or end of string), simply reverse the characters in-place. That would eliminate all the copying and concatenation.

One approach to reversing the characters in-place would be something like:

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

void strprev (char *begin, char *end);

int main (int argc, char **argv) {

    if (argc < 2) return 1;
    size_t len = strlen (argv[1]);

    char *p, *ep;
    char rev[len + 1]; /* a VLA is fine here   */

    strncpy (rev, argv[1], len + 1);     /* copy string to rev       */
    p = ep = rev;

    for (;;) {  /* for every char in rev */

        if (*ep && *ep != '\n') {        /* if not at end of rev, and */
            if (*ep == ' ' && ep > p) {  /* if ' ' and chars between  */
                strprev (p, ep - 1);     /* reverse between p and ep  */
                p = ep + 1;              /* advance p to next word    */
            }
        }
        else {  /* handle last word in rev */
            if (ep > p)
                strprev (p, ep - 1);
            break;
        }
        ep++;
    }

    printf ("\n string  : %s\n reverse : %s\n\n", argv[1], rev);

    return 0;
}

/** strprev - reverse string given by begin and end pointers.
*  Takes valid string and swaps src & dest each iteration.
*  The original string is not preserved.
*  If str is not valid, no action taken.
*/
void strprev (char *begin, char *end)
{
    char tmp;

    if (!begin || !end) {
        printf ("%s() error: invalid begin or end\n", __func__);
        return;
    }

    while (end > begin)
    {
        tmp = *end;
        *end-- = *begin;
        *begin++ = tmp;
    }
}

Output

$ ./bin/strrevex_a "ABC DEF GHI JKL MNO"

 string  : ABC DEF GHI JKL MNO
 reverse : CBA FED IHG LKJ ONM

Note: if you need to handle (skip) multiple spaces between the word, then they would need to be skipped before you assign p = ep + 1; in the code above.

If you are actually trying to reverse the entire string, that is quite a bit easier. Let me know which one is the correct goal and I'll help further if needed.



来源:https://stackoverflow.com/questions/32615231/reversing-words-within-a-string

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!