1

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.

Bence Kaulics
  • 7,066
  • 7
  • 33
  • 63
Anonymous
  • 11
  • 5
  • 4
    `ch2[&i]` this is wrong in so many ways, either `ch2` is not an array nor `&i` a valid index. (`&i` is a pointer, memory address of variable `i`). If `ch2 = ch` right after `getch()` call and you compare them after, they will always be the same. – Bence Kaulics Oct 18 '16 at 19:08
  • Think about how to initialize `ch2` so you avoid satisfying the `if (ch == ch2)` test on the first iteration. (pay attention to my test clause) – David C. Rankin Oct 18 '16 at 19:08
  • 1
    @BenceKaulics but it compiles cleanly... `ch2[&i]` is used as if it were `i[ch2]` which of course it is not. – Weather Vane Oct 18 '16 at 19:10
  • which is best way to do it? – Anonymous Oct 18 '16 at 19:10
  • 3
    Unrelated, your indentation following the last `else` is *severely* misleading. – WhozCraig Oct 18 '16 at 19:11
  • 1
    im very confused guys. im a beginner and i want your help..can any one give me an example for how to do it? – Anonymous Oct 18 '16 at 19:13
  • 1
    @A.Geo You will never learn if you let other people do your homework. You should debug it using your favorite debugger. – Fantastic Mr Fox Oct 18 '16 at 19:20
  • 2
    Apart from other improvements, the horrible error is `if (ch == ch2[&i])` which should be `if (ch == ch2)` and at the end of the loop `ch2 = ch`, but other mods will be required to follow this, for example you read a character into `ch` and copy that to `ch2` before you even enter the loop. – Weather Vane Oct 18 '16 at 19:22
  • Also if the `else` is not executed you can stuck in an infinite loop because `ch` cannot be changed. – Bence Kaulics Oct 18 '16 at 19:34
  • `ch = getchar(); // getting the line of text`. How?! http://man7.org/linux/man-pages/man3/getchar.3p.html – work.bin Oct 18 '16 at 19:34
  • 3
    @BenceKaulics As @WhozCraig pointed out his final `else` isn't bracketed, so `putchar(ch);` is all that will execute in the `else` condition. The indentation is "_severely_ misleading" indeed – yano Oct 18 '16 at 19:47
  • @yano Oh that's correct, I fell for that. – Bence Kaulics Oct 18 '16 at 19:49

3 Answers3

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]) {})

David C. Rankin
  • 81,885
  • 6
  • 58
  • 85
  • i am getting this errors Severity Code Description Project File Line Suppression State Error C4996 'sprintf': This function or variable may be unsafe. Consider using sprintf_s instead. To disable deprecation, use _CRT_SECURE_NO_WARNINGS. – Anonymous Oct 18 '16 at 20:06
  • 1
    Windows incorporates the `_s` proposed extensions to the C language (virtually no one else does). The warning is due to `sprintf` allowing writing beyond the end of your array if you do not check. You can use `snprintf` to limit the characters written (and retain code portability). In this case your duplicate check would be `snprintf (s, MAXL, " duplicate");` and the remainder would be `snprintf (s, MAXL-offset, " ..text...");` The warning is a windowism, but you can use `sprintf_s` as well if you like. Note: the parameters will be different. – David C. Rankin Oct 18 '16 at 20:13
  • To eliminate the warning, add `#define _CRT_SECURE_NO_WARNINGS` to the top of your code. You will run into this a lot if you are coding on windows. It doesn't mean the code is unsafe. Microsoft is quite creative in the ways it tries to drive people to their products. You can read more here [**Microsoft _s functions, are they part of the C++ standard now?**](http://stackoverflow.com/questions/617571/microsoft-s-functions-are-they-part-of-the-c-standard-now) – David C. Rankin Oct 18 '16 at 20:17
1

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)'.

Community
  • 1
  • 1
gaoithe
  • 4,218
  • 3
  • 30
  • 38
-1
  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;
}
Arnolio
  • 502
  • 3
  • 8
  • 1
    Getting error because on the if statement ch2 doesn't have value – Anonymous Oct 18 '16 at 20:08
  • 1
    whoops. I have learned the hard way always compile examples you post. :) Initialise ch2 something like ch2=0; before loop. Just one 'ch = getchar();' intended I presume. Getting the error about non initialised variable is an opportunity for learning. :-) Are you getting a warning or error about it ? Depending on your c compiler you might not get a warning - I don't (gcc 4.8.2). ch2 could be initialised to anything. It is a var on stack or in registers. – gaoithe Oct 18 '16 at 20:12
  • If I print ch2 not initialised I am getting 0x08 - a tab char. If I pass -Wall to gcc compiler I get warning "warning: ‘ch2’ is used uninitialized in this function [-Wuninitialized]" – gaoithe Oct 18 '16 at 20:21
  • I'm on OSX odly gcc didn't complain about the ch2=0 missing. But error indeed, fixed above as well as one more little bug. Let me know if you were able to get it to work – Arnolio Oct 19 '16 at 13:36
  • `ch = getchar(); ch = getchar();` is wrong. --> `ch = getchar();` – BLUEPIXY Oct 21 '16 at 04:11