C duplicate character,character by character

我只是一个虾纸丫 提交于 2019-12-24 08:27:18

问题


I am trying to find if two characters following by one another are the same character. ie if i have this input "The oldd woman" I want to print next to second D "duplicate". Here is my code but I can't find out how can I do this coding. Here is my code:

void main()
{
    char ch,ch2;
    ch = getchar(); // getting the line of text
    int i = 1;
    ch2 = ch;

    while (ch != '\n') // the loop will close if nothing entered
    {
        if (ch == ch2[&i]) {
            printf("%c-duplicate", ch);
        }
        i++;
        if (ch == 'A' || ch == 'E' || ch == 'I' || ch == 'O' || ch == 'U') { // checking for uppaercase vowel
            printf("%c-upper case vowel", ch);
        }
        else if (ch == 'a' || ch == 'e' || ch == 'i' || ch == 'o' || ch == 'u') { // checking for lowecase vowel
            printf("%c-lower case vowel", ch);
        }
        else if (ispunct(ch)) {          // checking for punctuation
            printf("%c-punctuation", ch);
        }
        else
            putchar(ch);

            printf("\n");
            ch = getchar();
        }
        printf("\n");
    }
}

I am setting the character to another variable and then checking them with the first if statement. The program should run character by character.


回答1:


Below is an example that I believe is what you intended. c is the current character being read (note: it is type int) and c1 is the previous character read (initialized to -1 to insure it does not match the first test).

While you can compare A and E..., the string library provides strchr that easily allows testing if a single character is included within a larger string.

Rather than call printf for each duplicate or vowel, etc.., why not use sprintf to build a string containing all the criteria applicable to any one character. That way you only call printf once at the end of each iteration (depending on whether you are printing all or just those that match criteria). s is used as the buffer that holds the match information for each character, offset is simply the number of characters previously written to s. (you should check to insure you don't exceed the number of characters available in s (but that was unneeded here)

It is unclear whether you want to print each character in the input string, or just those you have matched so far. The code below with only output those characters that match one of the criteria (if no argument is given). If you would like to see all characters, then pass any value as the first argument to the program.

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

#define MAXL 32

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

    char *uvowel = "AEIOU", *lvowel = "aeiou";
    int c, c1 = -1;

    while ((c = getchar()) != '\n' && c != EOF) {
        char s[MAXL] = "";              /* description buffer */
        int offset = 0;                 /* offset       */
        if (c == c1)                    /* new == old   */
            offset = sprintf (s, " duplicate");
        if (strchr (uvowel, c))         /* upper-case?  */
            sprintf (s + offset, " upper-case vowel");
        else if (strchr (lvowel, c))    /* lower-case?  */
            sprintf (s + offset, " lower-case vowel");
        else if (ispunct (c))           /* punctuation? */
            sprintf (s + offset, " punctuation");
        else if (argc > 1)              /* if printing all */
            sprintf (s + offset, " other");
        if (*s)                         /* print c and s   */
            printf (" %c - %s\n", c, s);
        c1 = c;                         /* save last char read */
    }

    return 0;
}

Example Use/Output

$ echo "The oldd woman" | ./bin/classdup
 e -  lower-case vowel
 o -  lower-case vowel
 d -  duplicate
 o -  lower-case vowel
 a -  lower-case vowel

Pass any value as the first argument to print all characters:

$ echo "The oldd woman" | ./bin/classdup 1
 T -  other
 h -  other
 e -  lower-case vowel
   -  other
 o -  lower-case vowel
 l -  other
 d -  other
 d -  duplicate other
   -  other
 w -  other
 o -  lower-case vowel
 m -  other
 a -  lower-case vowel
 n -  other

Duplicate vowels

$ echo "womaan" | ./bin/classdup
 o -  lower-case vowel
 a -  lower-case vowel
 a -  duplicate lower-case vowel

Look things over and let me know if you have any questions. There are many ways to do this, this is just one that seemed close to your intent.

(note: you will want to pass the -Wno-unused-parameter compiler option to eliminate the warning about argv being unused, or just do a stub test somewhere in the code, e.g. if (argv[1]) {})




回答2:


Worth answering to try and help understand variables and pointers I think.

To try and answer . . . as simply as possible . . . NOTE #1: the main problem/issue is that ch and ch2 are declared as single char variables. They can be 'a' or 'b' or '\n' or 0x20 or any other single char. They are NOT char arrays or pointers. You have a comment where you read one char 'ch = getchar() // getting the line of text', that comment is incorrect (although you do have good comments in showing what you are thinking in your example), anyway, this 'ch = getchar()' just gets a single char. Later you treat ch2 as an array.

char ch,ch2;
. . . then later:
if (ch == ch2[&i]) {   // ouch, does that even compile? yes. oh dear. how do we explain this one?! 

ouch! This is wrong because it treats ch2 as an array/pointer. The way your loop is working now is ch2 is set once to the very first char read. And it never changes.

It may compile okay BUT does it give a warning? Actually, in fairness to you. I do not get a warning. gcc 4.8.2 is perfectly happy with ch2 being a char and doing (ch == ch2[&i]). Now, ch2[&i] may be syntactically valid code, it will compile ok. It will even run ok. BUT what does it mean? Is it semantically valid? Let's forget about this weird thing until later.

Note that you can have c compiling fine BUT it can be quite full of pointer errors and can crash/hang. So . . . be careful :-).

Try making a change like this:

ch = getchar(); // does not get the line of text, just gets one char
. . . 
ch2 = 0; // for the first iteration of loop
if (ch == ch2) { // change from ch2[&i] - wow :-) very confused!
. . . 
    ch2 = ch; // set ch2 to the last char read before reading new
    ch = getchar(); // read one new char

This makes the code work just using 2 chars. ch and ch2. You do not use i. You do not use an array or string or char pointer.

NOTE #1.1: ch2[&i] compiles and runs. BUT IT IS WRONG, OHHHH SOOOOOO WRONG. And weird. How does array access work in c? The syntax of c[&i] is "correct" (maybe depends on compiler). BUT please do not use this syntax! What does it mean? It is semantically dubious. Looks like perhaps intent was to use array of chars together with i. Quick example showing assigning and reading from array of chars correctly:

char s[100]; // string of 100 chars, accessing index below 0 and above 99 is bad
i=0;
s[i]='H';    // assign char 'H' to first letter of string (s[0])
i++;         // increment i, i is now 2.
s[i]='i';
i++;
s[i]=0; // end string
printf("s[0]=%c s[1]=%c s[2]=%02x string:%s",s[0],s[1],s[2],s);

NOTE #1.2: ch2[&i] compiles and runs. How and why does it compile?

&i means the pointer to the variable i in memory

%p in printf will show pointer value

So try adding this to code sample:

printf("%p %p %p\n", &ch, &ch2, &i);

// ch2[i] will not compile for me, as ch2 is not an array. syntax error

// ch2[&i] DOES compile for me. But . . what is the value ? 
// What does it mean. I do not know! Uncharted territory.
printf("ch2[&i]:%p:%02x\n",&i,ch2[&i]);
printf("ch2[&ch]:%p:%02x\n",&ch,ch2[&ch]);
printf("ch2[&ch2]:%p:%02x\n",&ch2,ch2[&ch2]);

I'm getting something like this each run the pointers change:

ch2[&i]:0xbfa0c54c:bfa0de71
ch2[&ch]:0xbfa0c54a:08
ch2[&ch2]:0xbfa0c54b:00

The discovered explaination:

Usually we declare an array e.g. 'int array[100];' where 100 is the size of array. array[0] is first element and array[99] is the last. We index the array using integer. Now, all arrays are pointers. SO *array is the same as array[0]. *(array+1) is the same as array[1].

So far so good.

Now *(1+array) is also the same as array[1]. We can say int i=7; And use array[i] or *(array+7) or *(7+array) OR i[array] to show the 7th element of the array. i[array] to any programmer should look very VERY WROOOONG (not syntactically wrong BUT philosophically/semantically/morally wrong!)

Okay. Fine. Calm down. Jeez. Now with 'char ch2;' ch2 is a single char. It is NOT an array. ch2[&i] works(works as in compiles and sometimes/mostly runs ok!!!) because the last(WROOOONG) i[array] notation is valid. Looking at TYPES is interesting:

i[array] === <type int>[<type int *>]. 
ch2[&i] === <type char>[<type int *>]. 

C happily and merrily casts char to int and int can be added to pointer or used as pointer. SO FINALLY IN CONCLUSION: the syntax ch2[&i] evaluates to an integer at offset of: &i(pointer to integer i) PLUS value of char ch2. There is no good reason to use this syntax! It's DANGEROUS. You end up accessing a memory location which may or may not be valid and as your pointer is pointer to single variable the location in not valid in reference to any other values.

See here: Why 'c[&i]' compiles while 'c[i]' doesn't?

NOTE #2: watch the bracketing {}. while and main closing } and indentation do not match in example. The program functions okay with this error. The putchar(ch) runs as part of the last else. The commands after that run at end of while loop.

NOTE #3 main should return int not void main optionally takes nothing '()' or '(int argc, char**argv)'.




回答3:


  1. Per other suggestions: Change ch == ch2[&i] This makes no sense here
  2. Since you set ch = ch2 before the loop then the line if(ch == ch2 ) (After you fix it) will always evaluate to true the first time around
  3. Your else, is very confusing, if you have more than one line of code there you have to put in brackets
  4. Keep in mind, when you enter your input you are actually submitting two characters eg ("e" AND "\n") because you press enter after you type the character and that counts
  5. Try a little harder, meaning put an error message, put down the results of your attempts at a solution. It helps both us and you. It seems a little like you wrote this and just immediately want a fix. Programming gets harder, if you can't work through problems (with suggestions) then it's going to hurt a lot more, but it doesn't have to.

For a quick an dirty proof of concept, add another ch=getchar(); immediately after the one under your else. Note that the code below should run but doesn't do exactly what you want yet, you'll need to do some further debugging.

Edit 10/19/2016

Fixed the char2 issue you guys pointed out

Moved ch2 = ch to above the lines which get the new character

#include <stdio.h>
#include <ctype.h>

int main(){
    char ch,ch2;
    ch = getchar(); // getting the line of text
    int i = 1;
    ch2 = 0;

    while (ch != '\n') // the loop will close if nothing entered
    {
        if (ch == ch2) {
            printf("%c-duplicate", ch);
        }
        i++;
        if (ch == 'A' || ch == 'E' || ch == 'I' || ch == 'O' || ch == 'U') { // checking for uppaercase vowel
            printf("%c-upper case vowel", ch);
        }
        else if (ch == 'a' || ch == 'e' || ch == 'i' || ch == 'o' || ch == 'u') { // checking for lowecase vowel
            printf("%c-lower case vowel", ch);
        }
        else if (ispunct(ch)) {          // checking for punctuation
            printf("%c-punctuation", ch);
        }

        printf("\n");
        ch2 = ch;
        ch = getchar();
        ch = getchar();

    }


    printf("\n");
    return 0;
}


来源:https://stackoverflow.com/questions/40116073/c-duplicate-character-character-by-character

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