user930305
user930305

Reputation:

Removing characters inside parenthesis in C

I made a program that will delete characters inside a parenthesis. The inputted text should have matching open and close parenthesis.

Case 1:

Input:    (Hello) World
Output: World

Case 2:

Input:    (Hello World
Output: (Hello World

Case 3:

Input:    Hello)(World
Output: Hello)(World

Case 4:

Input:    Hello((hi) World)
Output: Hello

Case 5:

Input:    (Hello) hi (World)
Output: hi

Here's my code:

#include <stdio.h>
int main(){
    char string[100] = {0};
    char removedletters[100] = {0};
    fgets(string, 100, stdin);
    char *p;
    int x = 0;
    int b = 0;
    for (p=string; *p!=0; p++) {
        if (*(p-1) == '(' && x) {
            x = 0;
        }
        if (*p == ')') {
            x = 1;
        }
        if (!x){
            removedletters[b] = *p;
            b++;
        }
    }
    puts(removedletters);
}

Case 1, 3, and 5 are correct, but not in Case 2 and 4. What's wrong with my code?

Upvotes: 5

Views: 902

Answers (2)

paxdiablo
paxdiablo

Reputation: 881563

I'm not sure what's specifically wrong with that code but, for efficiency, I'd keep a stack of the last found ( characters and use that to remove portions whenever you find a ).

In semi-pseudocode:

// str is the input string, set up to and from pointers.
stacktype stack = empty-stack
char *from = str
char *to = str

// Process every character once and once only.
while *from != '\0':
    switch *from:
        // Open, transfer character and store position on stack.
        case '(':
            *to++ = *from++
            stack.push (to - 1)
            break

        // Close, get most recent '(' and adjust to for overwrite.
        //   If no most recent, just transfer as is.
        case ')':
            if stack is not empty:
                to = stack.pop()
            else:
                *to++ = *from++
            break

        // Anything else, just transfer.
        default:
            *to++ = *from++

// Terminate string at truncated position.
*to = '\0'

This will go through the string character by character, remembering all the ( positions in the stack but still transferring characters.

Whenever you find a ) character, you adjust the to pointer so that you start overwriting from the most recent ( character, effectively removing everything inside and including a (...) section.

Upvotes: 1

Sebastian Mach
Sebastian Mach

Reputation: 39089

You are invoking undefined behaviour:

for(p=string; *p!=0; p++){
    if(*(p-1) == '(' && x){
        x = 0;
    }

The first time p++ is evaluated is at the end of the loop-block, therefore, for the first time, *(p-1) is pointing one left of string, i.e. you are doing *(string-1).

Unfortunately, you lose any warranty if you have undefined behaviour.

Upvotes: 2

Related Questions