2

So I'm trying to make a script in C to show me the parity bit. Basically I need to input the binary of a converted character and as output I should have the input + either 1 or 0 (1/0 is the parity bit. 0 is even, 1 uneven). I just can't get it to work. I either get the same input or some crazy error. Can someone give me a hand? Thx

Here's the script

#include<stdio.h>
#include<stdlib.h>
#include<string.h>

int main (){    
   char msg_bit_input[128];    
   char msg_bit_output[128];    
   char caruno='1';    
   int i;    
   int one; 
   printf("Insert the byte: "); 
   scanf("%s", msg_bit_input);
   strcpy (msg_bit_output, msg_bit_input); 
   for(i=0;i<8;i++){        
       if(msg_bit_input[i]==caruno){            
           one--;
       }
   }

   if(one%2==0){        
       //byte is even        
       strcat (msg_bit_output, msg_bit_input);    
   } else if(one%2==1){
       //byte is uneven      
       strcat (msg_bit_output, msg_bit_input);
   }
   printf("The result is: %s", msg_bit_output);    
   return (EXIT_SUCCESS); 
}
Zenith
  • 33
  • 5
  • 5
    `one` is uninitialzed – Support Ukraine May 17 '20 at 19:19
  • Welcome to Stack Overflow. I advise you to try some simpler problems before you attempt this one. – Beta May 17 '20 at 19:19
  • 1
    Besides it being uninitialized (as already mentioned) `one--` seems odd (pun not intended). Why not `one++` to count the number of "ones"? – Some programmer dude May 17 '20 at 19:21
  • 2
    When it comes to programming it's often the case *less is more*. You have a test for `if (one % 2 == 0)` and then an `else if` which tests the only other possible outcome. Just use an `else`. It's not possible for that value to be anything other than `0` or `1` (unless you have negative numbers). – tadman May 17 '20 at 19:21
  • It's far from clear what your "parity" thing actually does here. It seems to concat the two strings together exactly the same way regardless of the outcome. – tadman May 17 '20 at 19:22
  • The string you are concatenating each time is the entire input string. – Weather Vane May 17 '20 at 19:27
  • So basically I need to check if the input has even or odd parity. The for loop should check if the value has an odd/ even parity by checking the number of 1 bits. The end result should be 01100001 (which is the letter 'a' in binary) + 1 or 0 – Zenith May 17 '20 at 19:35
  • This is a well-known problem; [software implementations](https://graphics.stanford.edu/~seander/bithacks.html#ParityWith64Bits). – Neil May 17 '20 at 19:44

1 Answers1

1

Let's Fix It

The minimal changes needed to get it to work are:

  1. You forgot to initialize the one counter.
  2. You should be counting up, not down (i.e. one++ not one--).
  3. You are not adding the parity bit to the output, but just duplicating the input.
  4. You need to add a terminating newline (\n) in the printf of the output.

With fixes, it is:

#include<stdio.h>
#include<stdlib.h>
#include<string.h>

int main (){    
   char msg_bit_input[128];    
   char msg_bit_output[128];    
   char caruno='1';    
   int i;    
   int one = 0;
   printf("Insert the byte: "); 
   scanf("%s", msg_bit_input);
   strcpy (msg_bit_output, msg_bit_input); 
   for(i=0;i<8;i++){        
       if(msg_bit_input[i]==caruno){            
           one++;
       }
   }
   if(one%2==0){        
       //byte is even        
       strcat (msg_bit_output, "0");    
   } else if(one%2==1){
       //byte is uneven      
       strcat (msg_bit_output, "1");
   }
   printf("The result is: %s", msg_bit_output);    
   return (EXIT_SUCCESS); 
}

Try it out online: https://onlinegdb.com/Bk30ef1s8.

Let's Simplify and Improve

But the program is unnecessarily complicated. First, it's not needed to use a separate output and input: you're taking input as-is and adding a parity bit to it. We simplify to:

//...
int main (){    
   char bits[128];    
   char caruno='1';    
   int i;    
   int one = 0;
   printf("Insert the byte: "); 
   scanf("%s", bits);
   for(i=0;i<8;i++){        
       if(bits[i]==caruno){            
           one++;
       }
   }
   if(one%2==0){        
       //byte is even        
       strcat (bits, "0");    
   } else if(one%2==1){
       //byte is uneven      
       strcat (bits, "1");
   }
   printf("The result is: %s", bits);    
   return (EXIT_SUCCESS); 
}

Try it: https://onlinegdb.com/S1UwWMksU

Then, we note that the test for even/odd parity can only have two outcomes - they are alternatives, so if the result is not even, we know it must be odd, so no need to check that:

//...
   if (one%2==0) 
       //byte is even        
       strcat (bits, "0");    
   else
       //byte is odd      
       strcat (bits, "1");
//...

Try it: https://onlinegdb.com/Skrc-Gki8

The use of the caruno variable is unnecessary: it's hardly a "magic constant", we quite know what it means!

int main (){    
   char bits[128];  
   int i;    
   int one = 0;
   printf("Insert the byte: "); 
   scanf("%s", bits);
   for(i=0;i<8;i++){        
       if(bits[i]=='1'){            
           one++;
       }
   }
//...

Try it: https://onlinegdb.com/ByAA-MkjU

We then notice that scanf has no way of knowing how long is the buffer it receives input into. If the user provides longer input, scanf will happily overflow that buffer and scribble all over the stack. We'd want the program to be robust in face of bad inputs - that's just a change to the scanf format argument, to provide the width. There's a caveat: scanf will always append the zero terminating character to the input, so we need to provide the buffer size less 1 to leave room for that zero:

   scanf("%127s", bits);

Try it: https://onlinegdb.com/SJJrqMyj8

And now we also notice that we don't really test whether there's room in the input string to append the output. Instead of appending the output, we can print it separately:

int main (){    
    char bits[128];  
    int i;    
    int one = 0;
    char result;
    printf("Insert the byte: "); 
    scanf("%127s", bits);
    for(i=0;i<8;i++){        
        if(bits[i]=='1'){            
            one++;
        }
    }
    if (one%2==0) 
        result = '0'; //byte is even       
    else
        result = '1'; //byte is odd

   printf("The result is: %s%c", bits, result);    
   return (EXIT_SUCCESS); 
}

Try it: https://onlinegdb.com/Bk0w9M1iU

One could argue that the limitation of input to just 8 bits seems unnecessary - you never check for it. If it were necessary, we could check for it explicitly.

Let's say we don't care whether the input is exactly 8 bits or not: we'll return whatever bits were entered, and append a parity bit. We do this by looping not over i, but using a pointer to the string buffer, and comparing the character to '\0' - that's the null terminator where we should break the loop. Note that the iterator (the bufp pointer) can point to const char, since we don't intend the loop to be modifying the characters.

At that point we can also detect invalid input that contains characters other than 0 or 1. We add the error function to print the error output. We can also get rid of the string.h header inclusion, since we don't use any string operations from that header:

#include <stdio.h>
#include <stdlib.h>

int error(const char *message)
{
    fprintf(stderr, "\nError: %s.\n", message);
    return EXIT_FAILURE;
}

int main (){    
    const char bits[128];  
    char *bitp;  
    int one = 0;
    char result;

    printf("Enter one or more binary bits: "); 
    scanf("%127s", bits);

    for (bitp = bits; *bitp != '\0'; ++bitp)
    {
        if (*bitp == '1')
            ++one;
        else if (*bitp != '0')
            return error("invalid input");
    }

    if (one%2==0) 
        result = '0'; //byte is even       
    else
        result = '1'; //byte is odd

   printf("The result is: %s%c", bits, result);    
   return (EXIT_SUCCESS); 
}

Try it: https://onlinegdb.com/B1Ux-XyiI

We should now test if we handle another input error condition - if there's a premature end of input stream. This can be triggered on windows by pressing Ctrl-Z then Enter (this closes the input stream to the console process), or by pressing Ctrl-D on Unix.

In onlinegdb, you can trigger this error condition by pressing ^D in the console window after you Run the program:

A screenshot showing the failure due to premature end of input

And Finally...

Finally, it would be a good idea to leverage more modern C features: you should declare and initialize the variables close to the point of use, so that they are easier to keep track of. The result variable can be initialized using the ternary operator expression, of the form: condition ? value_if_true : value_if_false. This entire expression becomes value_if_true if condition evaluated to true, or value_if_false if the condition evaluated to false. This helps with initialization at the point of declaration:

#include <stdio.h>
#include <stdlib.h>

int error(const char *message)
{
    fprintf(stderr, "\nError: %s.\n", message);
    return EXIT_FAILURE;
}

int main()
{
    char bits[128];  
    printf("Enter one or more binary bits: "); 
    scanf("%127s", bits);

    int ones = 0;
    for (const char *bitp = bits; *bitp != '\0'; ++bitp)
    {
        if (*bitp == '1')
            ++ones;
        else if (*bitp != '0')
            return error("invalid input");
    }

    char result = (ones%2==0) ? '0' /*even*/ : '1' /*odd*/;

    printf("The result is: %s%c", bits, result);    
    return EXIT_SUCCESS; 
}

Try it: https://onlinegdb.com/SJ1DbmJi8

And Finally, Finally :)

One thing I don't particularly like is the bug-prone repetition of buf length in both the variable declaration and in scanf's format string.

Let's try the suggestion from this answer, and factor out the string input into a separate function:

#include <stdio.h>
#include <stdlib.h>

int error(const char *message)
{
    fprintf(stderr, "\nError: %s.\n", message);
    return EXIT_FAILURE;
}

void scan_string(char *buffer, unsigned length) {
    char format[12]; // Support max int value for the format %<num>s
    snprintf(format, sizeof(format), "%%%ds", length - 1); // Generate format
    scanf(format, buffer);
}

int main()
{
    char bits[128];  
    printf("Enter one or more binary bits: "); 
    scan_string(bits, sizeof(bits));

    int ones = 0;
    for (const char *bitp = bits; *bitp != '\0'; ++bitp)
    {
        if (*bitp == '1')
            ++ones;
        else if (*bitp != '0')
            return error("invalid input");
    }

    char result = (ones%2==0) ? '0' /*even*/ : '1' /*odd*/;

    printf("The result is: %s%c", bits, result);    
    return EXIT_SUCCESS; 
}

Try it: https://onlinegdb.com/HyEsbQJoI

Kuba hasn't forgotten Monica
  • 95,931
  • 16
  • 151
  • 313