-4

I am getting right to the point because I cannot explain the situation that I am going to describe. I need your attention please!

Yesterday I wrote a program in C. The program takes as input a string and if that string is in this form "PKPKKKPPPKKKP", namely consists only 'P' and 'K' character it prints you YES or NO. YES if for a single 'P' character there is a match with a 'K' character. Exactly as we do with parenthesis characters problem '(', ')', only instead of '(' I had to use 'P' and instead of ')', 'K'.

With a little help from here I managed to finish the program and it was running correctly. I do not think that copying the code will help anyone, but I will explain how it works.

Program Description: The program takes a string (the string can be up to 500 length) as input, if the string consists only 'P' and 'K' characters it prints YES or NO, as I described above, otherwise it rejects it. Then it reads the input, character by character, and when it finds 'P' it is pushed in a stack, else pop. (I implemented the stack with linked list, so the user will be able to give as big a string he wants (or I thought so...)). Before the user typed a string, the symbol 'A' was in the stack. So the input was analyzing by the program, character by character and if it found a 'P' it was pushed to the stack, else pop the stack. If the top of the stack at the end was the 'A' character, the program was printing YES, else NO.

Problem Description: So I am with a friend of mine today,performing the program. Everything was ok. Until I pass as an input a really big string, like 300'P's and 300'K's (and remember my string is a char string[500]). It printed yes. Then I typed a string like 800'P's+800'K's. It didn't run correctly. Here is the problem, after that incident whatever if I type a string, a normal one "PKPKPK", it prints millions of weird symbols ( x └ X ╨ x └ X ╨ x ). I haven't touch the code, I swear! I compiled again, run again, the same! Its like something is wrong with my pc (Windows 10). And the problem continues to another program...I tried to make a a simple program just to function a stack implemented with linked list. I pushed the character 'a' and print it. It prints 'á'. I pushed the 'b'. It prints 'h'. I pushed the 'd'. It prints 'L'.

Obviously I should not have typed such a huge string because the limit of its length was 500. But the problem still exists! I cannot write a program with linked list anymore. I am desperate!

The code:

#include "stdio.h"
#define FIRST_SYMBOL_IN_STACK 'A'
#define TRUE 1
#define FALSE 0
#define STR_LENGTH 50
#define YES "YES"
#define NO "NO"
#define PLA 'P'
#define KAL 'K'

typedef struct node {
    char simvolo_eisodou;
    struct node *next;
} node; 

node *top = NULL; // the top of the stack

void push(char simvolo_eisodou); //stack function
int isStackEmpty(); //stack function
void pop(); //stack function
void printStack(); //print the current stack elements
int isInputValid(char *string); 
void printWelcome();

int main() {
    char input_string[STR_LENGTH], apantisi = 'G';  //O xristis mporei na dwsei input_string mikous ews 500 xaraktires
    push(FIRST_SYMBOL_IN_STACK);
    int i = 0;
    scanf("%s", input_string);

    if (isInputValid(input_string)) {
        while (input_string[i] != '\0') {
            if (input_string[i] == PLA) {
                push(PLA);
                printStack();
            } else {
                pop();
                printStack();;
            }
            i++;
        }
    } else {
        printf("Den anagnwristike to %s, input_string=(P|K)*\n");
        _exit(-1);
    }

    if (top->simvolo_eisodou == FIRST_SYMBOL_IN_STACK) {
        printf("%s\n", YES);
    } else {
        printf("%s\n", NO);
    }

    return 0;
}

void push(char simvolo_eisodou) {
    node *newNode = (node*)malloc(sizeof(node));
    newNode->simvolo_eisodou = simvolo_eisodou;
    newNode->next = top;
    top = newNode;
    free(newNode);
}

int isStackEmpty() { //Thewrw oti i stoiva einai adeia otan i korifi einai to arhiko simvolo
    if (top->simvolo_eisodou == FIRST_SYMBOL_IN_STACK) {
        return TRUE;
    }
    return FALSE;
}

void pop( ){
    if (isStackEmpty()) {
        printf("KENO\n");
        printf("%s\n", NO);
        _exit(-1);
    }
    node *temp = top;
    top = top->next;
    free(temp);
}

void printStack() {
    node *current = top;
    while (current != NULL) {
        printf("%c ", current->simvolo_eisodou);
        current = current->next;
    }
    free(current);
    printf("\n");
}

int isInputValid(char *string) {
    int i = 0;
    while (*(string + i) != '\0') {
        if (!(*(string + i) == 'P' || *(string + i) == 'K')) {
            return 0;
        }
        ++i;
    }
    return 1;
}

void printWelcome() {
    printf("\n====================================================================\n");
    printf("Welcome\n");
    printf("====================================================================\n");
    printf("\n\n\n Plz type input_string=(P|K)*\n");
}
chqrlie
  • 131,814
  • 10
  • 121
  • 189
Mr T
  • 506
  • 2
  • 9
  • 26
  • 2
    "I do not think that copying the code will help anyone". That's a very wrong thinking. The problem is almost certainly bugs in your code causing Undefined Behaviour. Please post the code in the question itself (not as an external link). What do you think happens to the memory `top` is pointing to after this code runs: `top=newNode; free(newNode);`? And then what do yo think happens later when you try to access the data pointed to by `top`? – kaylum Mar 02 '16 at 22:07
  • Hmm I wonder what happens if you try to put more items in an array than the array has items, hmmm I wonder why that would give you issues... – EDD Mar 02 '16 at 22:08
  • @kaylum top=newNode; means that the top points to newNode so I do not need newNode anymore, and thus i free it! Correct? – Mr T Mar 02 '16 at 22:11
  • Absolutely incorrect. If I give you the address of my house and then physically destroy my house can you still access my house? A pointer, `top` in this case, is just an address to some memory. If you `free` the memory then the pointer becomes invalid and dereferencing it is Undefined Behaviour. – kaylum Mar 02 '16 at 22:12
  • I can assure that actual code is a thousand times better than a text description of the code . Not sure what you do for a job but try to imagine a similar situation in your line of work – M.M Mar 02 '16 at 22:12
  • But @kaylum by freeing a pointer I am destroying the address, not the house right? And dont forget it was running correctly! – Mr T Mar 02 '16 at 22:14
  • @M.M I am putting the code! – Mr T Mar 02 '16 at 22:14
  • 2
    No. You destroyed the house. The pointer is just an address to the physical house. Look up "Undefined Behaviour". It means you can not predict what will be the result - it may crash immediately, not crash but produce wrong results, appear to work sometimes, etc. And the behaviour may change on recompilation, or different runs of the same program, etc. So totally unpredictable. – kaylum Mar 02 '16 at 22:15
  • What is your question exactly? As far as I can tell it seems like you are saying "I overflowed my buffer on purpose and it prints weird things", and you haven't asked a question anywhere. – M.M Mar 02 '16 at 22:15
  • Why `#include "stdio.h"` and not `#include `? and also you call `malloc` but `stdlib.h` is missing. is this a JOKE? – Michi Mar 02 '16 at 22:15
  • @M.M OP is saying he overflowed the buffer once. And now his program does not work anymore even on seperate runs. OP basically does not know about Undefined Behaviour. – kaylum Mar 02 '16 at 22:16
  • There is not possible way that this code compiles even with the worst compiler. – Michi Mar 02 '16 at 22:17
  • @Michi it compiles in `gcc -std=c11 -pedantic` (with warnings, which OP obviously should fix) – M.M Mar 02 '16 at 22:21
  • I compiled it with microsoft's windows compiler! @kaylum thanks! – Mr T Mar 02 '16 at 22:21
  • `printf("Den anagnwristike to %s, input_string=(P|K)*\n");` What should be exactly printed with `%s` here? – Michi Mar 02 '16 at 22:22
  • @M.M I hope not. This code has [tooooo](http://pastebin.com/raw/Ag7G5Ezi) many problems. – Michi Mar 02 '16 at 22:24
  • The *undefined behaviour* perhaps assured that when you overflowed the buffer ***once*** the program will never run correctly again, on any planet. – Weather Vane Mar 02 '16 at 22:25
  • 1
    @M.M [How is that possible](http://pastebin.com/raw/4UcMWz5u) ? – Michi Mar 02 '16 at 22:27
  • @kaylum My friend you where right!!! Thanks a lot! M.M thanks for the effort! I should delete that question now right? – Mr T Mar 02 '16 at 22:28
  • You should ask him to post the solution as an answer. – Weather Vane Mar 02 '16 at 22:29
  • @kaylum can you post that thing with the addresses as an answer? So I can tick it! – Mr T Mar 02 '16 at 22:31
  • @Skemelio Do you have your own `stdio.h` header file ? – Michi Mar 02 '16 at 22:31
  • @Michi gcc tries very hard to be friendly, apparently – M.M Mar 02 '16 at 22:35
  • @M.M could be, but OP's code has to many problems which aren't actually just warnings. and if that piece of code does compiled, well I'm a happy guy, because I gave up on Microsoft from more than 10 Years :D. – Michi Mar 02 '16 at 22:39
  • @Michi it compiled in GCC (as you showed). I don't see any reason to target MS. Most people expect the compiler to help them make a program, rather than fight every step of the way – M.M Mar 02 '16 at 22:44
  • @M.M I meant something else and I deleted my comment :) . Any way this is wrong I think :D I tough that `-pedantic` should be avoided ? – Michi Mar 02 '16 at 22:50
  • @Michi `-std=c11 -pedantic` means to comply with C11 standard as much as possible (the standard requires that the compiler output a diagnostic message, which it did). – M.M Mar 02 '16 at 22:53
  • @M.M Thank you for your explanation, I learn every day something new. Any way i use `GCC-5.3` which I think that has included default `c11` – Michi Mar 02 '16 at 22:54
  • I highly doubt that you broke your computer. If your linked list program doesn't work, then that's probably just because your linked list program is broken too. – user253751 Mar 02 '16 at 23:43
  • I stopped at ' I need your attention please!' – Martin James Mar 03 '16 at 00:30

2 Answers2

4

Your code has Undefined Behaviour (UB). The result of running code with UB is unpredictable. It can sometimes appear to work but there is no guarantee that the same result will occur each and every time.

At least one source of your UB is this code:

top=newNode;
free(newNode);

Once newNode is freed the top pointer becomes invalid and any dereferencing of that pointer will result in UB.

kaylum
  • 13,833
  • 2
  • 22
  • 31
2

Your code starts off with:

#define STR_LENGTH 50

// ...  in main
char input_string[STR_LENGTH];
scanf("%s", input_string);

In your question you talk about a buffer of length 500. But there is no such buffer in your code, the length is 50.

If you type in 50 or more characters then you cause undefined behaviour. This means that anything can happen. There is no possible way you can control what happens in this case and you should not expect any particular behaviour.

The only way to fix the problem is to stop overflowing the buffer. You must change your code so that there is no overflow.

Your program description is that it should support up to 500 characters in the string. One way to achieve this would be:

char input_string[501];   // +1 for terminator
scanf("%500s", input_string);   // IMPORTANT: 500 limiter

If you wanted to report an error if they typed too much, instead of just ignoring it, you could then write:

if ( !isspace(getchar()) )    // requires #include <ctype.h>
{
    fprintf(stderr, "Too many characters entered - aborting program");
    exit(EXIT_FAILURE);
}

for example.

If you actually want to support an arbitrary length of input then you would need to switch to a more complicated memory strategy (e.g. a linked list, or reallocating a buffer as the input grows).


Other notes on your code:

  • You use functions from #include <stdlib.h> so you must have that line
  • printf("Den anagnwristike to %s, input_string=(P|K)*\n") has a %s but no corresponding argument, this also causes undefined behaviour
  • Use exit(EXIT_FAILURE) instead of _exit(-1);

NB. There may be other issues as well, I didn't check your whole program.

Community
  • 1
  • 1
M.M
  • 138,810
  • 21
  • 208
  • 365
  • If the OP's code is the whole code then Microsoft's compiler should be avoided. – Michi Mar 02 '16 at 22:34
  • @M.M thanks for your effort. I know that overflowing the buffer is a problem too but sometimes its working. My problem was that I could not understand how free() works. I thought it frees the memory space of a pointer, not where a pointer points to. Unfortunately I can mark only one question correct! – Mr T Mar 02 '16 at 22:38
  • 1
    @Michi: As MSVC is not standard compliant anyway, this is good advice in general. – too honest for this site Mar 02 '16 at 22:40
  • @Olaf Alles klar :)). I will never use Microsoft products this mean that I will never know something about it . – Michi Mar 02 '16 at 22:41