Homework about bit sequence in C - c

I have a homework. The question is:
Write a function that takes as parameter a single integer, int input, and returns an unsigned character
such that:
a- if input is negative or larger than 11,111,111 or contains a digit that is not 0 or 1; then the function will
print an error message (such as “invalid input”) and return 0,
b- otherwise; the function will assume that the base-10 value of input represents a bit sequence and return the magnitude-only bit model correspondent of this sequence.
For Example: If input is 1011, return value is 11 and If input is 1110, return value is 14
This is my work for a, and I am stuck on b. How can I get bit sequence for given integer input?
int main()
{
int input = 0;
printf("Please type an integer number less than 11,111,111.\n");
scanf("%d",&input);
if(input < 0 || input > 11111111)
{
printf("Invalid Input\n");
system("PAUSE");
return 0;
}
for (int i = 0; i < 8; i++)
{
int writtenInput = input;
int single_digit = writtenInput%10;
if(single_digit == 0 || single_digit == 1)
{
writtenInput /= 10;
}
else
{
printf("Your digit contains a number that does not 0 or 1. it is invalid input\n");
system("PAUSE");
return 0;
}
}
printf("Written integer is %d\n",input);
system("PAUSE");
return 0;
}

The bit that you are missing is the base conversion. To interpret a number in base B, what you need to do is multiply digit N times B^N (assuming that you start counting digits from the least significative). For example, in base 16, A108 = (10)*16^3 + 1*16^2 + 0*16^1 + 8*16^0. Where in your base is 2 (binary).
Alternatively, you can avoid the exponentiation if you rewrite the expression as:
hex A008 = ((((10*16) + 1)*16 +0)*16 + 8
Which would be simpler if your input was stated in terms of an array of possibly unknown length as it is easily convertible into a loop of only additions and multiplications.
In the particular case of binary, you can use another direct solution, for each digit that is non-zero, set the corresponding bit in an integer type large enough (in your case, unsigned char suffices), and the value of the variable at the end of the loop will be the result of the conversion.

First off, the existing part of your code needs work. It doesn't report non-binary digits correctly. The question is "Are there any digits that are neither 0 nor 1". To answer this question in the negative, you need to check every single digit. Your code can terminate early. I also suggest renaming the function to something that clearly tells you what it does. For example haveNonBinaryDigit. The term check doesn't tell you what you should expect on the return value.
As for the second part, read up on the binary representation. It is fairly similar to decimal, except that instead of each digit being weighted by 1, 10, 100, .., 10^x, they are weighted by 1, 2, 4, ..., 2^n. Also the digits can only have values 0 and 1.

Your current code has a problem: it will terminate as soon as it finds one single binary bit (at the end) and call the entire integer correct.
I would take a different approach to this problem. What you want to do is get your hands on every single digit from the integer seperately. You made a good start in doing so by using modulo. Say you had this code:
for (int i = 0; i < 8; i++)
{
char single_digit = input%10;
input /= 10;
}
This makes it easy to start working with the digits. You would be checking 8 bits because that seems to be the maximum allowed (11,111,111). Check if each digit is either 0 or 1. Then you can start pushing it in to an unsigned character using bitwise operations. Shift every digit to the left by i, then use a bitwise OR.

Related

Why does a high-value input prevent an array from using the actual input value in C?

I'm making a function that takes a value using scanf_s and converts that into a binary value. The function works perfectly... until I put in a really high value.
I'm also doing this on VS 2019 in x64 in C
And in case it matters, I'm using
main(int argc, char* argv[])
for the main function.
Since I'm not sure what on earth is happening, here's the whole code I guess.
BinaryGet()
{
// Declaring lots of stuff
int x, y, z, d, b, c;
int counter = 0;
int doubler = 1;
int getb;
int binarray[2000] = { 0 };
// I only have to change things to 1 now, am't I smart?
int binappend[2000] = { 0 };
// Get number
printf("Gimme a number\n");
scanf_s("%d", &getb);
// Because why not
printf("\n");
// Get the amount of binary places to be used (how many times getb divides by 2)
x = getb;
while (x > 1)
{
d = x;
counter += 1;
// Tried x /= 2, gave me infinity loop ;(
x = d / 2;
}
// Fill the array with binary values (i.e. 1, 2, 4, 8, 16, 32, etc)
for (b = 1; b <= counter; b++)
{
binarray[b] = doubler * 2;
doubler *= 2;
}
// Compare the value of getb to binary values, subtract and repeat until getb = 0)
c = getb;
for (y = counter; c >= 1; y--)
{
// Printing c at each subtraction
printf("\n%d\n", c);
// If the value of c (a temp variable) compares right to the binary value, subtract that binary value
// and put a 1 in that spot in binappend, the 1 and 0 list
if (c >= binarray[y])
{
c -= binarray[y];
binappend[y] += 1;
}
// Prevents buffer under? runs
if (y <= 0)
{
break;
}
}
// Print the result
for (z = 0; z <= counter; z++)
{
printf("%d", binappend[z]);
}
}
The problem is that when I put in the value 999999999999999999 (18 digits) it just prints 0 once and ends the function. The value of the digits doesn't matter though, 18 ones will have the same result.
However, when I put in 17 digits, it gives me this:
99999999999999999
// This is the input value after each subtraction
1569325055
495583231
495583231
227147775
92930047
25821183
25821183
9043967
655359
655359
655359
655359
131071
131071
131071
65535
32767
16383
8191
4095
2047
1023
511
255
127
63
31
15
7
3
1
// This is the binary
1111111111111111100100011011101
The binary value it gives me is 31 digits. I thought that it was weird that at 32, a convenient number, it gimps out, so I put in the value of the 32nd binary place minus 1 (2,147,483,647) and it worked. But adding 1 to that gives me 0.
Changing the type of array (unsigned int and long) didn't change this. Neither did changing the value in the brackets of the arrays. I tried searching to see if it's a limit of scanf_s, but found nothing.
I know for sure (I think) it's not the arrays, but probably something dumb I'm doing with the function. Can anyone help please? I'll give you a long-distance high five.
The problem is indeed related to the power-of-two size of the number you've noticed, but it's in this call:
scanf_s("%d", &getb);
The %d argument means it is reading into a signed integer, which on your platform is probably 32 bits, and since it's signed it means it can go up to 2³¹-1 in the positive direction.
The conversion specifiers used by scanf() and related functions can accept larger sizes of data types though. For example %ld will accept a long int, and %lld will accept a long long int. Check the data type sizes for your platform, because a long int and an int might actually be the same size (32 bits) eg. on Windows.
So if you use %lld instead, you should be able to read larger numbers, up to the range of a long long int, but make sure you change the target (getb) to match! Also if you're not interested in negative numbers, let the type system help you out and use an unsigned type: %llu for an unsigned long long.
Some details:
If scanf or its friends fail, the value in getb is indeterminate ie. uninitialised, and reading from it is undefined behaviour (UB). UB is an extremely common source of bugs in C, and you want to avoid it. Make sure your code only reads from getb if scanf tells you it worked.
In fact, in general it is not possible to avoid UB with scanf unless you're in complete control of the input (eg. you wrote it out previously with some other, bug free, software). While you can check the return value of scanf and related functions (it will return the number of fields it converts), its behaviour is undefined if, say, a field is too large to fit into the data type you have for it.
There's a lot more detail on scanf etc. here.
To avoid problems with not knowing what size an int is, or if a long int is different on this platform or that, there is also the header stdint.h which defines integer types of a specific width eg. int64_t. These also have macros for use with scanf() like SCNd64. These are available from C99 onwards, but note that Windows' support of C99 in its compilers is incomplete and may not include this.
Don't be so hard on yourself, you're not dumb, C is a hard language to master and doesn't follow modern idioms that have developed since it was first designed.

How to get total numbers of digits used in an integer in c language?

We all know that we can get numbers of characters in an string using strlen() function, but if I want to get a number of the digits used in an integer, how can I do it?
Like if there is 1000 stored in a variable a and that variable is an integer type, I want to get length of the number and that is 4.
If you know the number is positive, or you want the minus sign to be included in the count:
snprintf(NULL, 0, "%d", a);
If you want the number of digits in the absolute value of the number:
snprintf(NULL, 0, "+%d", a) - 1;
The key to both these solutions is that snprintf returns the number of bytes it would have written had the buffer been large enough to write into. Since we're not giving it a buffer, it needs to return the number of bytes which it would have written, which is the size of the formatted number.
This may not be the fastest solution, but it does not suffer from inaccuracies in log10 (if you use log10, remember to round rather than truncate to an integer, and beware of large integers which cannot be accurately converted to a double because they would require more than 53 mantissa bits), and it doesn't require writing out a loop.
What you're asking for is the number of decimal digits. Integers are stored in a binary format, so there's no built-in way of determining that. What you can do to count the decimal digits is count how many times you can divide by 10.
int count = 1;
while (a >= 10) {
a /= 10;
count++;
}
Not really sure if I got your question right, but given your example, as far as I could understand you want to know how many digits there are in a given number (for example: 1 has one digit, 10 has two digits, 100 has three digits, so on...). You can achieve it using something like this:
#include <stdio.h>
int main(void){
int numberOfDigits = 0, value;
scanf("%d", &value); //you scan a value
if (value == 0)
numberOfDigits = 1;
else{
while (value != 0){
numberOfDigits++;
value = value / 10;
}
}
printf("Number of digits: %d\n", numberOfDigits);
return 0;
}

How do I populate an array with the digits of a given integer in C? [duplicate]

This question already has answers here:
convert an integer number into an array
(8 answers)
Closed 7 years ago.
So lets say you have an integer in your code declared
int my_num = 967892;
and you have an array
int a[6];
How would you put that integer into the array so it looks like this?
{ 9, 6, 7, 8, 9, 2 }
Perhaps like this:
const unsigned char digits[] = { 9, 6, 7, 8, 9, 2 };
but there are many things that are unclear with your question, of course.
If you want to do this at runtime, as your comment now makes me believe, you need more code of course. Also, it will be tricky to make the array "fit" the number exactly, since that requires runtime-sizing of the array.
The core operation is % 10, which when applied to a number results in the rightmost digit (the "ones" digit).
You can do this by getting each digit and putting it into an array. Kudos to #unwind for thinking of using unsigned int because digits don't have signs. I didn't think of that.
DISClAIMER: this code is untested but would, theoretically, if I haven't made any mistakes that the community will catch, accomplish your task.
NOTE: This program is implementation-defined when theNum is negative. See this SO question for more info on what that means. Also, the accepted answer in the question of which this post is a duplicate has shorter code than this but uses log10 which (according to commenters) could be inaccurate.
//given theNum as the number
int tmp = theNum;
int magnitude = 0;
//if you keep dividing by 10, you will eventually reach 0 (integer division)
//and that will be the magnitude of the number + 1 (x * 10^n-1)
for (; tmp > 0; magnitude++){ //you could use a while loop but this is more compact
tmp /= 10;
}
//the number of digits is equal to the magnitude + 1 and they have no sign
unsigned int digits[magnitude];
//go backwards from the magnitude to 0 taking digits as you go
for (int i = magnitude - 1; i > 0; i--){
//get the last digit (because modular arithmetic gives the remainder)
int digit = theNum % 10;
digits[i] = digit; //record digit
theNum /= 10; //remove last digit
}
If this shall be done dynamically:
Determine the number of digits as N.
Allocate an array large enough (>=N) to hold the digits.
Loop N times chopping of the digits and storing them in the array allocated under 2.
The least significant digit is num % 10
The next digit can be found by num/=10;
This works for positive numbers, but is implementation defined for negative
I assume you want to achieve something like this:
int arr[SOME_SIZE];
int len = int_to_array(arr,421);
assert(len == 3);
assert(arr[0] == 4);
assert(arr[1] == 2);
assert(arr[1] == 1);
Since this is probably a homework problem, I won't give the full answer, but you'll want a loop, and you'll want a way to get the last decimal digit from an int, and an int with the last digit removed.
So here's a hint:
421 / 10 == 42
421 % 10 == 1
If you want to create an array of the right length, there are various approaches:
you could loop through twice; once to count digits (then create the array); once again to populate
you could populate an array that's bigger than you need, then create a new array and copy in as many members as necessary
you could populate an array that's bigger than you need, then use realloc() or similar (a luxury we didn't used to have!)

Recursive function to convert between number bases fails at certain numbers

I'm trying to a create an algorithm that can convert base 10 numbers into base n numbers, where n is at most 10. However, for some weird reason the following algorithm in C fails at certain critical points for each base. For example, for base 2 and base 3 conversions, all numbers up to and including 1023 and 52,487 work, respectively, but numbers beyond that produce some weird negative result. I can't figure out why this is happening; can anyone help me?
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int returnint;
int baseconvert(int number,int base) {
if(number == 0 || base == 10) {
return returnint;
}
returnint = (number % base) + (10 * baseconvert(number / base, base));
return returnint;
}
int main() {
fprintf(stdout,"%d\n",baseconvert(1023,2));
fprintf(stdout,"%d\n",baseconvert(52487,3));
}
EDIT:
Here is the printed result of the above print statements, if that's helpful:
1410065408
-2094967296
Your algorithm is very limited in the range of numbers vs. bases. The smaller the base is the more digits are needed to represent it. And since you store the result in decimal form, you'll waste your available data range very quickly. There is no fundamental data type that can hold the results for all the possible inputs. E.g., maximal 31-bit decimal number (normal integer, dropping the sign bit) will result in 31-digit output!
You have several options to cope with this:
Allocate a stack large enough and push the digits into it. Upon completion, print the stack contents.
Print the digits immediately without saving, this will eliminate the need to allocate anything.
E.g.:
#include <stdio.h>
void baseconvert(int number,int base)
{
if(number > 0)
{
int digit = (number % base);
baseconvert(number / base, base);
printf("%d",digit);
}
else
{
printf("\n");
}
}
int main()
{
baseconvert(1023,2);
baseconvert(52487,3);
}
It appears that the integer value is overflowing. For example, the decimal value 1023 in base two is 1111111111. If it is a 4 byte integer, then it will overflow when trying to "add" one more digit (the max signed integer in this case being 2147483647).
Since it appears your goal is to display a number in a different base, it might make more sense to store the digits in a character array.
On all processors that I know of, integers are already stored in binary form; this implies base 2. This value can be displayed in whatever base you desire, with some work on your part. printf() and friends allow you to easily print in base 10 (%d) and base 16 (%x). It is not difficult to imagine a method that would convert a binary (base 2) integer value into a character representation in base n.
I seriously doubt that you really intend to change the actual value of the integer, as you are doing. Like #ThoAppelsin said above, the number of apples in the bag stays the same, regardless of which base you choose for display.
By simply creating a method that represents (with digits) the integer in any base, you will also solve your overflow problem!
Your result is overflowing the integer range. Try using strings instead. This is the pseudocode which relies on strings to represent numbers and it can convert numbers from any base to any other base between 2 and 36 inclusive (using digits and upper case letters):
function ConvertNumber(number, b, d)
begin
newNumber = ""
while number <> "0"
begin
number = Divide(number, b, d, out remainder)
newDigit = ValueToDigit(remainder)
newNumber = Concatenate(newDigit, newNumber)
end
if newNumber ="" then
newNumber = "0"
end
function Divide(number, base, divisor, out remainder)
begin
remainder = 0
result = ""
for i = 0 to Length(number) - 1
begin
digitValue = DigitToValue(number[i])
remainder = base * remainder + digitValue
newDigitValue = remainder / divisor -- integer division
remainder = remainder mod divisor
if newDigitValue > 0 OR result <> "" then
newDigit = ValueToDigit(newDigitValue)
result = Concatenate(result, newDigit)
end
if result = "" then
result = "0"
return result
end
You can find the whole math and implementation in this article: Converting Number Bases.

What does the condition "if (n/10)" with integral n specify?

I am looking at the following piece of code:
void printd(int n)
{
if (n < 0) {
putchar('-');
n = -n;
}
if (n / 10)
printd(n / 10);
putchar(n % 10 + '0');
}
I understand the first if statement fine, but the second one has me confused on a couple of points.
By itself, since "n" is an integer, I understand that n/10 will shift the decimal point to the left once - effectively removing the last digit of the number; however, I am having a little trouble understanding how this can be a condition by itself without the result being equal to something. Why isn't the condition if ((n/10) >= 0) or something?
Also, why is the '0' passed into the putchar() call?
Can someone tell me how it would read if you were to read it aloud in English?
Thanks!
The n / 10 will evaluate to false if the result is 0, true otherwise. Essentially it's checking if n > 10 && n < -10 (the -10 doesn't come into play here due to the n = -n code)
The + '0' is for character offset, as characters '0'-'9' are not represented by numbers 0-9, but rather at an offset (48-57 with ascii).
Can someone tell me how it would read if you were to read it aloud in English?
If you're talking about the conditional, then I would say "if integer n divided by 10 is not zero"
n/10 will not shift the decimal number since n is an integer. The division will produce the result like this: if n = 25, then n/10 would be 2 (without any decimal points), similarly if n = 9, then n/10 would be 0 in which case if condition would not be satisfied.
Regarding the +'0', since n%10 produces an integer result and in putchar you are printing a char , you need to convert the integer to a char. This is done by adding the ascii value of 0 to the integer.
In C, there is no separate boolean type; an expression like a > b evaluates to zero if false, non-zero if true. Sometimes you can take advantage of this when testing for zero or non-zero in an int.
As for the '0', that just performs character arithmetic so that the right character is printed. The zero character has an ASCII encoding value which isn't zero, so the n value is used as an offset from that encoding to get the right numeric digit printed out.

Resources