-1

With the code below, I'd always run into "Stack around the variable 'UserCode' was corrupted.

If I'm not mistaken, when I do userCode = (char*)malloc(sizeof(char)*N);, shouldn't it create an "array" with size of char*n ? I'm guessing my issue is either with my declaration of an array, or my pointer arithmetic.

Any help would be highly appreciated.

#include "stdafx.h"
#include <math.h>

int userPrompt1() {
    int numOfAlphabets = 0;
    printf("Please enter a number from 1 to 8 to choose how many alphabets you want\n");
        scanf_s(" %d", &numOfAlphabets);
        if (numOfAlphabets > 8 || numOfAlphabets < 0) {
            printf("Sorry! Invalid number entered. Try again. \n");
            numOfAlphabets = userPrompt1();
        }
        return numOfAlphabets;
}

int userPrompt2() {
    int numOfLetters = 0;
    printf("Please enter the number of letters you want to guess\n");
    scanf_s(" %d", &numOfLetters);
    if (numOfLetters < 0) {
        printf("Sorry! Invalid number entered. Try again. \n");
        numOfLetters = userPrompt2;
    }
    return numOfLetters;
}

int tryCalculator(int K, int N) {
    int tries = 0;
    tries = 1 + ceil(N * log2(K));
    return tries;
}

void codeGenerator(char codeGuessIn[], char letters[], int size) {
    for (int i = 0; i < size; i++) {
        int rando = rand() % size;
        codeGuessIn[i] = letters[rando];
        printf(" %c", codeGuessIn[i]);
    }
    printf("\n");
}

void codeChecker(char codeGuessIn[], char generatedCode[], int size) {
    int correctAlphabets = 0;
    for (int i = 0; i < size; i++) {
        if (codeGuessIn[i] == generatedCode[i]) {
            correctAlphabets++;
        }
    }
    printf(" %d in correct place \n", correctAlphabets);
}

void getUserCode(int size, char *userCode[]) {
    for (int i = 0; i < size; i++) {
        printf("Please enter letter #%d \n", i+1);
        getchar();
        scanf_s(" %c", &userCode[i]);
    }
}


int main(void)
{
    char letters[8] = { 'A','B','C','D','E','F','G','H' };
    char *generatedCode;    //array to hold generated code
    char *userCode;         // array to hold generated code.
    int K = userPrompt1();  //how many different alphabets in code
    int N = userPrompt2();  //how many letters in code
    int tries = tryCalculator(K, N);
    //int gameEnd = 1;

    userCode = (char*)malloc(sizeof(char)*N);
    generatedCode = (char*)malloc(sizeof(char)*N);
    codeGenerator(generatedCode, letters, N);
    getUserCode(N, &userCode);
    //codeChecker(userCode, generatedCode, N);


    return 0;
}
Junyu Teoh
  • 13
  • 2
  • 1
    `numOfLetters = userPrompt2;` typo – BLUEPIXY Jun 10 '17 at 20:54
  • Please read [this question and answers about casting the result of `malloc`](http://stackoverflow.com/questions/605845/do-i-cast-the-result-of-malloc). The consensus is that you should not do it. Also, `sizeof(char)` is defined by the C specification to *always* be `1`. – Some programmer dude Jun 10 '17 at 20:54
  • 2
    As for the problem, don't pass a pointer to the pointer to `getUserCode`. Everything with your use of the `userCode` pointer in the call and in the function is wrong. – Some programmer dude Jun 10 '17 at 20:56
  • 1
    @Some programmer dude: it is disputable, it is not the axiom. – 0___________ Jun 10 '17 at 21:03
  • `scanf_s(" %c",` need size parameter. – BLUEPIXY Jun 10 '17 at 21:03
  • Thank you @Someprogrammerdude. I was not aware of the issues I would face by casting, as my lecturer did not say anything of it and actually encourages the use of it. I will try to find another way about creating an array with size N. – Junyu Teoh Jun 10 '17 at 21:05
  • @PeterJ Considering that I don't see any explicit inclusion of `` the casting might actually be dangerous. – Some programmer dude Jun 10 '17 at 21:06
  • @JunyuTeoh That's how you dynamically allocate an "array", it's just the casting that might be problematic. – Some programmer dude Jun 10 '17 at 21:07
  • @BLUEPIXY you mean `scanf_s( "%1c",` ? I tried that, but it still gives me the error. But I get what you mean, I should make it a habit to include a size parameter. – Junyu Teoh Jun 10 '17 at 21:08
  • @Some programmer dude: In this case is not. In both (int *) and (char *) cast does nothing. The code with the cast and without will be the same – 0___________ Jun 10 '17 at 21:09
  • @JunyuTeoh See [example of scanf_s](https://msdn.microsoft.com/en-us/library/w40768et.aspx) E.g `scanf_s(" %c", &userCode[i], 1);` Also `void getUserCode(int size, char *userCode[]) {` --> `void getUserCode(int size, char *userCode) {`, and Call `getUserCode(N, &userCode);` --> `getUserCode(N, userCode);` – BLUEPIXY Jun 10 '17 at 21:09
  • @JunyuTeoh Please read e.g. [this `scanf_s` (and family) reference](http://en.cppreference.com/w/c/io/fscanf). – Some programmer dude Jun 10 '17 at 21:09
  • 1
    "shouldn't it create an "array" with size of char*n" - No. `malloc` returns a `void *` to a memory block of `N` bytes. It does not have a concept of types. That's why you should not cast the result. – too honest for this site Jun 10 '17 at 21:10
  • @PeterJ If `` is not included, then the `malloc` function will be implicitly declared with the first call, with a return type of `int`. If `sizeof(int) != sizeof(char *)` (which is most likely true on all 64-bit systems) then the pointer will be incorrect. – Some programmer dude Jun 10 '17 at 21:11
  • @Some programmer dude if there is no function prototype our discussion is pointless as the malloc result will be misinterpreted anyway. Lets do not discuss such a silly situations. – 0___________ Jun 10 '17 at 21:24
  • 2
    @PeterJ And that's what I've been saying all along. That if there's no prototype declared the cast will silence the compiler from complaining about incorrect type conversions. That's why casting can be so dangerous. – Some programmer dude Jun 10 '17 at 21:27
  • 1
    @Some programmer it is all about bad programming. Casting is hiding one of the minimum two warnings. You will get _warning: implicit declaration of function ....._ anyway. If someone ignores warnings, he will ignore another ones as well, and not casting will not help at all. Last month I was hired to check and repair someone's code. In two and a half thousend lines I got more than 200 warnings, which this guy has had actually ignored. – 0___________ Jun 10 '17 at 21:47
  • Thank you everyone for the links. I am sorry that my code had so many errors.. I really should've read the documents more. I'm rather ashamed of my question right now :/ – Junyu Teoh Jun 10 '17 at 22:27

1 Answers1

1
void getUserCode(int size, char *userCode[]) {
    scanf_s(" %c", &userCode[i]);

Here, userCode[i] is a char * (pointer-to-char), &userCode[i] is a char ** (pointer-to-pointer-to-char), and scanf("%c") expects a char *. A good compiler would warn about that.

I think what you meant to do here is something like:

void getUserCode(int size, char *userCode) {
    scanf_s(" %c", &userCode[i]);
}
int main(void) {
    char *userCode = malloc(N);
    getUserCode(N, userCode);
}

The printf(), getchar(), scanf() combination here reeks of the bad habits created by scanf: you're discarding the first character entered by the user because you're relying on an extra character in the input buffer. See http://c-faq.com/stdio/scanfprobs.html and read full lines of input with fgets() instead of using scanf().

Also,

int userPrompt2() {
    int numOfLetters = 0;
    ...
        numOfLetters = userPrompt2;
}

You're assigning a function pointer to an int. (A normal compiler should warn about this.) If the idea here is to call the function again to repeat the prompt in case the user enters something silly, it's probably a better idea to use a loop instead of a recursive call anyway.

ilkkachu
  • 6,221
  • 16
  • 30
  • Thank you for the explanation! I have implemented your suggested changes. And you were right at dissecting my thought process, I did want it to repeat if the user enters something silly. – Junyu Teoh Jun 10 '17 at 22:29