Combining two strings into one string which elimin

2019-08-29 09:51发布

问题:

Hello i'm so new in the programming and want to learn some from you :) I'm doing a program in .c and i am stucked in a part. I want to get 3 or more inputs max size of 5 characters. (For example: HELLO, HI, GOOD, BYE) And i want to stack them in a new string which holds same letters only once from those 4 strings (Example: H,E,L,L,O,I,G,D,B,Y)

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

int main(void) {
char first[5], second[5], third[5], fourth[5];
printf("Enter 1st word: \n");   scanf(" %5s", &first);
printf("Enter 2nd word: \n");   scanf(" %5s", &second);
printf("Enter 3rd word: \n");   scanf(" %5s", &third);
printf("Enter 4th word: \n");   scanf(" %5s", &fourth);

char stack[21];  // i want a new string like this and then combine first 4 strings
                 // in this string...

return 0;
}

I hope you can let me know with which way i can do it. (I'm also new in the site. I searched for this but i couldn't find. Sorry if it exists.)

回答1:

First some comments on your code:

  • As somebody else has already mentioned in a comment, you need a buffer of size n + 1 to hold an n character string. This is because in C, the length of a string is not stored anywhere. Instead, a special NUL byte is appended to the string that marks its end. Therefore, your first, …, fourth arrays should be of length at least 6.
  • What if the worst case happens and a user enters four disjoint words each worth 5 characters? Then your combined string will count 20 characters. So your stack array should be able to accommodate 21 characters (again 1 for the terminating NUL byte). (Also mentioned by user3121023's comment.)
  • To read a string using scanf, pass an argument of type char *, not char (*)[6]. first already decays to char * so don't additionally take its address (as in &first). Turn on your compiler's warnings (use at least -Wall) to be informed about such bugs. (Also mentioned by Dere0405 while I was typing this answer.)
  • Your use of scanf is insecure. If the user inputs a string longer than 5 characters, you'll read beyond the end of your array. You could modify the format specifier to read %5s to tell scanf to stop reading after the 5th character. However, this will leave excess characters at the end of the line. A better option would be to use fgets or getline to read an entire line of input. Alternatively, simply pass the strings as command line arguments (my preferred solution).

Now to the actual problem:

I won't give you a complete solution but only some hints because this looks very much like homework. (Unfortunately, someone else has already given you the full code so you will likely ignore my answer.)

You'll have to loop over all five strings and check for each character if it was already added to the stack. If so, continue, otherwise, append it to the stack. To loop over a string, we can use the following idiom.

int i;
for (i = 0; first[i]; ++i)
  printf("The character at position %d is '%c'\n", i, first[i]);

Alternatively, if we don't need to refer to the current index, the following idiom is more compact.

char * pos;
for (pos = first; *pos; ++pos)
  printf("The current character is '%c'\n", *pos);

Note how we use the fact that first – being a C string – is terminated with a NUL byte which evaluates to false. Otherwise, we would not know where to stop iterating.

Now that we know how to loop over the characters of a string, how can we check whether a character was already added? Two solutions come into mind:

  1. Loop over stack and compare each element to the current character in question. While for your short strings, this might be the method of choice, it will grow inefficient for longer strings.

  2. Create a counter for each character and increment it whenever added to stack. You can use the fact that chars are just numbers. So you could create an array with 256 elements (there are 256 different chars) all initially set to 0 and then increment the position for the character currently added. For example:

    int counters[256];
    memset(counters, 0, sizeof(counters));  /* fill with 0s */
    

    And then later in your code:

    if (counters[(unsigned char) (*pos)]++)
      {
        /* Character was already added.  Do nothing. */
      }
    else
      {
        /* Character was not added yet.  Add it to stack. */
      }
    

    The if (counters[(unsigned char) (*pos)]++) is a little tricky. First, *pos dreferences the pointer pos to yield the current character which is then interpreted as an unsigned char because arrays cannot have negative indices. That position is then looked up in the counters array and evaluated in the if statement. Finally, the value is incremented (but only after comparing) via the post-increment operator.

Don't forget to terminate stack with a NUL byte at the end.



回答2:

Please update your code as following:

printf("Enter 1st word: \n");   scanf(" %s", &first);

to

printf("Enter 1st word: \n");   scanf(" %s", first);

Please update to other lines.



回答3:

Try:

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

int main(void) {
    char strings[4][6];
    printf("Enter 1st word: \n");   scanf(" %s", strings[0]);
    printf("Enter 2nd word: \n");   scanf(" %s", strings[1]);
    printf("Enter 3rd word: \n");   scanf(" %s", strings[2]);
    printf("Enter 4th word: \n");   scanf(" %s", strings[3]);

    char stack[21];  // This needs to be pretty much bigger than all combined just in case

    // Initialize the stack string to 0 length
    stack[0] = '\0'

    // Move through each word
    for(unsigned char word = 0; word < 4; word++){

        // Move through each letter of each word
        for(unsigned char letter = 0; letter < strlen(strings[word]); letter++){
            // Test to see if the current letter is within the current stack string
            unsigned char schar;
            for(schar = 0; schar < strlen(stack); schar++){
                if(stack[schar] == strings[word][letter]) break;
            }

            if(schar >= strlen(stack)){
                unsigned char sstacklen = strlen(stack);
                stack[sstacklen] = strings[word][letter];
                stack[sstacklen+1] = '\0';
            }

        }
    }

    return 0;
}

This should work for what you are wanting, this was a quick write, so there may be small errors!