0

I’m trying to solve some exercises in preparation for an incoming test and i’ve encountered a problem that i’ve fixed by chance and i’d like to understand what’s going on with my code.

The exercise requires me to create a struct type that represent a monomial of 4 variables (x, y, w and z) and two functions, print_term that will show the monomial on screen and read_term, that take an user input and returns a monomial. The exercise requires the user input to be of the form “C V P V P V P V P .”, where C is the coefficient of the monomial, V is one of the 4 variables (in any order) and P is their power.

//Here is the monomial struct
struct term{
    int coef;
    int potx;
    int poty;
    int potw;
    int potz;
};

My problem lies in the read_term function: sometimes, if C is negative the power of one of the variables will be set to -48 (which definitely come from my attempt to convert the char that represent a digit to it’s value in int): for example, the input “-257 x 2 z 3 w 1 .” will return me -257(x^2)(w^-48)(z^3), while “257 x 2 z 3 w 1 .” will instead return the correct result 275(x^2)w(z^3).

struct term read_term(){
    struct term result;
        result.coef =0;
        result.potx =0;
        result.poty =0;
        result.potw =0;
        result.potz =0;
        
    char input[255];
    for(int i =0; i < sizeof(input)/sizeof(input[0]);i++){
        input[i] = '\0';
    }
    char inputNeg[255];
    int negativo = 0;

    printf("Termine: \n");      
                            
    fgets(input, 255, stdin);
    input[strlen(input)-1] = '\0';      //should remove '\n'


    //I remeve the minus sign, i'll add it back in later.
    if(input[0] == '-'){

        negativo = 1;
        int i = 1;
        do{
            inputNeg[i-1] = input[i];
            i++;
        }while(input[i] != '\0');   
        printf("\n%s\n", input);
        strcpy(input, inputNeg); 
        printf("\n%s\n", input);   
    }
   
    ////////////THIS MAKE OR BRAKE THE CODE
    
    //printf("\ninput prova\n");
    for(int i =0; i < sizeof(input)/sizeof(input[0]);i++){
       //printf("%c", input[i]);
    }

    ////////////////////////////

    //Change struct term result based on input:
    int index = 0;
    int cifreCof[12];
    for(int j=0; j< sizeof(cifreCof)/sizeof(cifreCof[0]);j++){
                cifreCof[j] = 0;
    }
    int temp = 0;
    int pot = 0;

    do{
        //Coeff is always at index 0
        if(index == 0){
            //Conversion from char to int
            do{
            cifreCof[index] = input[index] - '0';
            index++;
            pot++;
            }while(input[index] != ' ');

            //Puts all the digits in one int
            for(int i=0; i < sizeof(cifreCof)/sizeof(cifreCof[0]); i++){
                temp = temp + (cifreCof[i]*pow(10, pot-1));
                pot--;
            }

            //Place the minus sign back.
            if(negativo == 0){
                result.coef = temp;
            }
            else{
                result.coef = (-1)*temp;
            }
           
        }
        // Variabili.
        else{
            //White space
            if(input[index] == ' '){
                index++;
            }
            //x char
            else if(input[index] == 'x'){
                index++;
                index++;
                //per ora mi limito ad esponenti a una cifra
                if(input[index] != '.'){
                    result.potx = input[index] - '0';
                    index++; 
                }
                else{index++;}
            }
            //y char
            else if(input[index] == 'y'){
                index++;
                index++;
                //per ora mi limito ad esponenti a una cifra
                if(input[index] != '.'){
                    result.poty = input[index] - '0';
                    index++; 
                }
                else{index++;}
            }
            // w char
            else if(input[index] == 'w'){
                index++;
                index++;
                //per ora mi limito ad esponenti a una cifra
                if(input[index] != '.'){
                    result.potw = input[index] - '0';
                    index++; 
                }
                else{index++;}
            }
            //z char
            else if(input[index] == 'z'){
                index++;
                index++;
                //per ora mi limito ad esponenti a una cifra
                if(input[index] != '.'){
                    result.potz = input[index] - '0';
                    index++; 
                }
                else{index++;}
            }
            else{index++;}
        }

    }while(input[index] != '\0');
       
    return result;
}

In an attempt to identify the problem, i placed a for loop to print the array i use to save the input, just to discover that this loop changed the outcome of the function to the correct result: i decided to keep the loop but emptying it of its code, and still the result is correct. I have no idea how it fix my code but it does. Any explanation?

jps
  • 20,041
  • 15
  • 75
  • 79
Prio216
  • 35
  • 3
  • 1
    `inputNeg` does not get null terminated. – Ian Abbott Jun 22 '22 at 11:49
  • If you change it to `int i = 0;` `do{` `i++;` `inputNeg[i-1] = input[i];` `}while (input[i] != '\0');` then `inputNeg` will be null-terminated. But you do not really need `inputNeg` at all because you could modify `input` directly. – Ian Abbott Jun 22 '22 at 11:56
  • 1
    in this loop `while(input[index] != ' ')`, what if there is no space in the input? – stark Jun 22 '22 at 12:01
  • @IanAbbott you're right, the problem was the missing null in inputNeg and as you pointed out i can easily modify the input array without the use of inputNeg. I still don't understand what the empty for loop does, but your input definitely help fixing the problem. – Prio216 Jun 22 '22 at 12:33
  • @stark that shouldn't be happening since the exercise requires the user to end is input always with a white space and a point, so even the case where the user inputs a integer should require at least one white space. – Prio216 Jun 22 '22 at 12:37
  • @SupportUkraine - I just ran it. With all the variables initialized (which I believe is the only problem here in terms of run-time veracity) the double calls to `printf` returned first `-1 2 3 4 5 6 7 8 9` then `1 2 3 4 5 6 7 8 9`. As would be expected. I think the only purpose must be for OP to observe that the negative is being handled. – ryyker Jun 22 '22 at 13:23
  • @SupportUkraine - I did run it in original state (with uninitialized variables) also, for myself, and as you observed in the comment under my post, the problem did not present itself for me. That section of code produced the same two stings of output. But I think your question was good, in that it may have been that with OP's system the uninitialized variables could very well have resulted in other output. – ryyker Jun 22 '22 at 13:29

1 Answers1

0

It is very unlikely the empty loop had anything to do with fixing your code. But undefined behavior may have played a role in exposing the problem.

When a variable is created, the contents of memory allocated is unknown. Therefore, if it is used before being initialized, the results will be unpredictable.

A simple initialization will work:

char inputNeg[255] = {0};//initializes all elements of array in one step.

Although the for loop does initialize the array here

char input[255];
for(int i =0; i < sizeof(input)/sizeof(input[0]);i++){
    input[i] = '\0';
}

...initialization during declaration is more efficient:

char input[255] = {0};

Do the same for cifreCof

Regarding removing the newline after calling fgets, consider using this method:

//input[strlen(input)-1] = '\0';//unsafe for an empty string
input[strcspn(input, "\n")] = 0;//this is safe, and will remove newline
ryyker
  • 22,849
  • 3
  • 43
  • 87
  • You bring the same point of Ian Abbot and like him you're right, inputNeg not being initializated is what creates problem. I thank both of you since you did point out a big mistake and helped me to fix it, but i still wonder what the for loop does to fix the problem. Does the simple act of iterating without any code somehow add a null char at the end of the array? I don't get why that loop was helping me before. – Prio216 Jun 22 '22 at 12:44
  • @Prio216 - The empty loop you speak of is a red herring. It did nothing toward making the code run. However, using a block of memory for which the contents is unknown can lead to undefined behavior. This in turn means [anything can happen](http://www.catb.org/jargon/html/N/nasal-demons.html). Therefore, I believe the primary (and likely the only) issue is not fully initializing all variables before using them. Initialize all variables, then run your code (without the `printf` for loop) and see what happens. – ryyker Jun 22 '22 at 13:11
  • 1
    I fully agree with you that the missing initialization of my arrays was the problem, as I stated in the previous comment i've already fixed it thanks to your input and the code act as expected. I was just curious about the loop, but your link made me curious about the "anything can happen" so I went back to test other inputs. Turns out that if my coefficient start to get larger than 4 digits, the loop actually achieve nothing, so it really was just placebo and unexpected behavior. Thank you for your help! – Prio216 Jun 22 '22 at 13:28
  • @SupportUkraine thank you for your input, you guys were right and the fact that the loop "solved" the problem was just a lucky unexpected behavior that stopped working when the digits grow larger. – Prio216 Jun 22 '22 at 13:31