Why is printf producing strange output in my simple script? - c

I am an intermediate Python programmer, but I am trying to learn C. It is an extremely frustrating experience so far.
Why does this simple code...
#include <stdio.h>
#include <string.h>
char name[15] = "George Lopez"; /* string representing your name */
char birthday[6] = "01-30-92"; /* string representing your bday */
int phone_number; /* declair int representing phone number */
int main() {
phone_number = 2222223333; /* int representing your phone number */
printf("You said your name was: %s\n", name);
printf("And your birthday is %s?\n", birthday);
printf("And, so I can call you, your number is %d\n", phone_number);
return(0); /* exit program normally */
}
produce this output when the phone number is 2222223333:
You said your name was: George Lopez
And your birthday is 01-30-92?
And, so I can call you, your number is -2072743963
This output when the phone number is 9992223333:
error: 4_1_myinfo.c:16:3: warning: overflow in implicit constant conversion [-Woverflow]
phonenumber = 9992223333;
And this output when the phone number is 1112223333:
You said your name was: George Lopez
And your birthday is 01-30-92?
And, so I can call you, your number is 1112223333
I suspect this has to do with how C deals with integers. Perhaps, ints in C have a smaller maximum length than ints in python and this is resulting in wanky output?

You have a couple of major issues here.
First, when using C-strings, avoid defining the size of the buffer if you can, like so:
char name[] = "George Lopez"; /* string representing your name */
char birthday[] = "01-30-92"; /* string representing your bday */
If you MUST pre-defined the maximum string length, use a common limit, like so:
#define MAX_STR_LEN 256
char name[MAX_STR_LEN] = "George Lopez"; /* string representing your name */
char birthday[MAX_STR_LEN] = "01-30-92"; /* string representing your bday */
If you don't plan on modifying them in the future, make them const like so:
const char* name = "George Lopez"; /* string representing your name */
const char* birthday = "01-30-92"; /* string representing your bday */
In your case, you defined a character array that could only hold 6 characters, but tried to stuff 9 characters in it "01-30-92", plus the trailing \0 character included automatically. Big mistake.
The second major issue is that you are attempting to fit an integer literal into a data type which can not hold it. In C, the maximum signed 32-bit value, 2,147,483,647, is defined as INT_MAX in <limits.h>. You should make your code like so:
long long int phone_number = 2222222222L;
Notice the trailing numeric literal suffix, L? That's to allow your code to compile, and using a long long int is necessary to create a variable that can actually store the value itself.
Finally, you should consider using strings to hold the phone number. You aren't doing any algebraic/mathematical manipulations on it, so there's no need to use an integral data type to represent it.
Code Listing (Modified)
#include <stdio.h>
#include <string.h>
char name[] = "George Lopez"; /* string representing your name */
char birthday[] = "01-30-92"; /* string representing your bday */
long long int phone_number; /* declair int representing phone number */
int main() {
phone_number = 2222223333L; /* int representing your phone number */
printf("You said your name was: %s\n", name);
printf("And your birthday is %s?\n", birthday);
printf("And, so I can call you, your number is %lld\n", phone_number);
return(0); /* exit program normally */
}
Sample Output
You said your name was: George Lopez
And your birthday is 01-30-92?
And, so I can call you, your number is 2222223333

I think the better way to deal with phone numbers is to consider them as a string. You'll need a string type for "formatting" your outputs and also to verify that a phone number follow a certain "regular expression" when considering user inputs.

In C all datatypes have a fixed size. Typically an int is a 32 bit value (but it doesn't have to be) so it will have a maximum value of 2,147,483,647.
Your value, 9,992,223,333 exceeds this value, which it why you are getting a warning. You need to use a bigger datatype like a 64 bit number. This will typically either be a long long if you're on Windows, or a long if you're on Linux.

To understand why this is happening, you need to understand how the numbers are represented in memory. I will try to give you a glimpse of the basic way they work and some further references in case you are interested. As the computer understands just 0 and 1, base 2 is the obvious choice. But there is a problem with representing negative numbers. There are some representations, like the sign-magnitude representation (basically, have a bit that represents the sign - if it is set, the number is negative), that are very simple. The problem is that such representations have 2 ways of representing 0: +0 and -0. So, a clever representation, called two's complement is used. For a binary number abcd (where a, b, c, d represent its bits), the base 10 value is a*2^3+b*2^2+c*2^1+d*2^0. If this number was a 2's complement 4-bit representation, its base 10 value would be -a*2^3+b*2^2+c*2^1+d*2^0. So, in two's complement, the first bit has a negative weight. In a 4-bit two's complement representation, if you have 0111 (decimal 7) and you try to add 1, you will get 1000, which is -8. This is called an overflow. Overflow arises just when adding numbers with the same sign and obtaining a result of different sign (adding 2 positive numbers results a negative number or adding 2 negative numbers results a positive number).
In your program, something similar happens. The only difference is that int has 32 bits, not 4.
Further references:
http://en.wikipedia.org/wiki/Binary_number
http://en.wikipedia.org/wiki/Signed_number_representations

The range of a signed 32-bit integer is [-2147483648, 2147483647]. You try to represent your phone number as a signed integer.
a. When phone num is 1112223333, it's less than the max 2147483647, so you get theright output.
b. 2222223333 is greater than the max 2147483647, but can still be represented as a 32-bit number, you get the 2's complement number which is -2072743963
c. 9992223333 cannot be represented by a 32-bit number, i.e. it's even bigger than (2^32 - 1), that's why you such error.

Related

How to check whether a hexadecimal number(%x) starts with a certain number or not in C?

I'm working on an operating system related project now and there is one step which requires to check whether a hexadecimal number starts with 3 or not, using C.
Currently my idea is to convert that hexadecimal number into a string and check the initial character but just cannot find out any documentation for doing that. Anybody has any idea? Maybe just a hint.
There are lots of methods to convert a number to a hex string (sprintf comes to mind; How can I convert an integer to a hexadecimal string in C? list a few more) – but, why should you?
A full hex number is formed by converting each nibble (4 bits) to a hexadecimal 'digit'. To get just the first, you can divide your value by 16 until you have reached the final (= 'first', in the left-to-right notation common for both decimal and hexadecimal values) digit. If that's a 3 you are done.
Assuming value is an unsigned number:
while (value > 15)
value >>= 4;
and then check if value == 3.
Your idea is not bad, you can use sprintf, it functions like printf/fprintf but instead of printing
on screen (or to be more precise: writing into a FILE* buffer), it stores the contents in a char buffer.
char value[16]; // more than enough space for 4 byte values
int reg = 0x3eef;
sprintf(value, "%x", reg);
if(value[0] == '3')
printf("The hexadecimal number 0x%s starts with a 3.\n", value);

create number 0 only using int in the C

#include <stdio.h>
struct real_num
{
int int_num;
int frac_num;
};
void main()
{
struct real_num num1;
printf("input the number : ");
scanf("%d.%d",&num1.int_num,&num1.frac_num):
printf("%d.%d",num1.int_num,num1.frac_num);
}
i input 12.012 but buffer save 12.12 i want a 012 but this buffer save 12
what should i do? i want a save 012 (using only int)
Numbers are a matter of arithmetic. 1, 01, 1.0, 1.000, 0x01, 1e0 all describe the same number: whichever representation you use has the same mathematical properties, and behaves identically in calculation (ignoring the matter of computer storage of numbers as int or float or double... which is again another matter entirely).
The representation of a number is a matter of sequences of characters, or strings. Representations of numbers can be formatted differently, and can be in different bases, but can't be calculated with directly by a computer. To store leading zeroes, you need a string, not an int.
You typically convert from number representation to number at input, and from number to number representation at output. You would achieve your stated desire by not converting from number representation to number at input, but leaving it as a string.
You don't want to store 012, you want to store 0.012.
The value 0.012 in binary is (approximately):
0.00000011000100100110111010010111b
..and the value 12.012 is (approximately):
110.00000011000100100110111010010111b
Note that 0.012 is impossible to store precisely in binary because it would consume an infinite number of bits; in the same way that 1/3 can't be written precisely in decimal (0.333333333.....) because you'd need an infinite number of digits.
Let's look at 12.012. In hex it's this:
0x0000000C.03126E97
This makes it easier to see how the number would be stored in a pair of 32-bit integers. The integer part in one 32-bit integer, and the fractional part in another 32-bit integer.
The first problem is that you're using signed 32-bit integers, which means that one of the bits of the fraction is wasted for a sign bit. Essentially, you're using a "sign + 31 bit integer + wasted bit + 31 bit fraction" fixed point format. It'd be easier and better to use an unsigned integer for the fractional bits.
The second problem is that standard C functions don't support fixed point formats. This means that you either have to write your own "string to fixed point" and "fixed point to string" conversion routines, or you have use C's floating point conversion routines and write your own "floating point to fixed point" and "fixed point to floating point" conversion routines.
Note that the latter is harder (floating point is messy), slower, and less precise (double floating point format only supports 53 bits of precision while you can store 62 bits of precision).
A fraction does not consists of a single integer. A fraction consists of 2 integers: numerator/denominator.
Code needs to keep track of width of the fraction input. Could use "%n" to record offset in scan.
#include <stdio.h>
struct real_number {
int ipart;
int num;
int den_pow10;
};
void main(void) {
struct real_number num1;
printf("input the number : ");
fflush(stdout);
int n1 = 0;
int n2 = 0;
scanf("%d.%n%d%n",&num1.ipart, &n1, &num1.num , &n2):
if (n2 == 0) {
fprintf(stderr, "bad input\n");
return -1;
}
num1.den_pow10 = n2 - n1;
printf("%d.%*0d",num1.ipart,num1.den_pow10, num1.frac_num);
return 0;
}
Input/Output
input the number : 12.00056
Result 12.00056

Parsing a number with more than 10 digits in C

I'm trying to calculate UPC codes using C as a language, but I'm now having a problem with the precision. I tried int, float, long long, etc.
Here's the code:
#include <stdio.h>
int main(void)
{
float upc;
printf("Enter UPC:\n");
scanf ("%d", &upc);
printf("upc = %f ", upc);
}
the results are :
Enter UPC code:
123456789012
upc = 123456790528.000000 d= 1
Process returned 30 (0x1E) execution time : 6.672 s
Press any key to continue.
How can I show the number as is? It's only 12 digits.
I'm using CodeBlocks, is there an IDE that can handle this better?
Note: please don't tell me to just use char! I want to make some calculations later.
Universal product codes are not subject to integer arithmetic operations, so it doesn't entirely make sense to represent them using int. Each digit is assigned a particular meaning, so a string makes more sense.
If you really just want a band-aid, uint64_t from <stdint.h> will always be able to hold a 12-digit number. Do not use a floating-point type, though, as they are not designed to hold exact integers, but rather to approximate real numbers.
The correct way to use uint64_t with printf and scanf is with the fixed-width format specifiers from <inttypes.h>:
scanf ( "%" SCNd64, &upc);
printf("upc = %" PRId64 "\n", upc);
A float can typically store just 6-7 decimal digits. A 32-bit int can store 9 digits (10 if the leading digits is 3 or less). To store a 12-digit integer, you need to use either a long long (up to 18 digits) or perhaps a double (up to 15-16 digits), though a double is less desirable.
Hence:
#include <stdio.h>
int main(void)
{
long long upc;
printf("Enter UPC:\n");
scanf ("%lld", &upc);
printf("upc = %lld\n", upc);
return(0);
}
Actually can you be more clear of what you want as your output? I suggest you one modification in to use long long int instead of float.

Converting from long to hex in C?

I have this code
char binary[] = "0001001010000011";
long number = strtol(binary, NULL, 16);
printf("%x", number);
I want to convert the string into a hex number. the answer is 1283, but i am getting DF023BCF what am i doing wrong?
The base you specify to strtol is the base to use to parse the input, not the output (which instead is specified by the %x). IOW, that code says to strtol to parse 0001001010000011 as if it were a hexadecimal number (and, by the way, it results in overflow).
The last parameter to strtol is the base that you want to convert from. Since you are providing a binary encoded string you should specify a base 2 conversion.
Here is the correct code:
char binary[] = "0001001010000011";
long number = strtol(binary, NULL, 2);
printf("%x", number);
I would also suggest that binary numbers are not normally signed (especially when 17 digits long), therefore, it seems likely that you may want to use the unsigned version of the function, strtoul() as shown below. Finally, when printf'ing a number into hex format it might be a good idea to indicate hexadecimal with a leading 0x marker. In your case, the answer is 0x1283 but displaying this number as 1283 allows it to be easily confused as a decimal number. Both suggestions are shown below.
const char binary[] = "0001001010000011";
unsigned long number = strtoul(binary, NULL, 2);
printf("0x%x", number);

Convert a string of hexadecimal digits into integer

I am trying to implement the htoi(s) [Dennis Ritchie chapter2 exercise 2-3 Q] which converts a string of hexadecimal digits, into its equivalent integer, can anyone help me out in the logic of this program, i dont need the code, i just need the logic for implementing it. I am not able to get the correct logic
Let's take a step back:
How would you implement a function that accepts a single hex digit and returns it's decimal equivalent?
In other words, how would you write this function:
unsigned int hextodec(char c)
{
... your code here
}
Hint: for decimal digits what happens when you calculate c -'0'?
Once you have this function it should be fairly easy to use it to calculate the conversion of longer hex strings.
Hint: 0xF is 15 and 0x10 is 16
Use the strtol function with base 16.
About this way:
#include <stdio.h>
#include <stdlib.h>
#include <errno.h>
int xstrtol16(const char *s)
{
errno = 0;
char *endp = NULL;
int result = strtol(s, &endp, 16);
if (*charp || errno) {
fprintf(stderr, "Failed to convert...\n");
exit(1);
}
return result;
}
Think about what a printable number (in any base) is. Basically a list of symbols which represent simple numeric values (0...base-1), and associated "weights" of their digit positions. For decimal the symbols are "0123456789" and the weights are 1, 10 , 100, 1000...
You convert the printable number into "integer" by finding the corresponding numeric value of each symbol, multiplying it times the weight for that digit position, and summing those products together. There are tricks to doing this efficiently, but a straight-forward "dumb" implementation can get the job done perfectly well.
Hex is slightly complicated because there are two runs of symbols -- 0-9 and A-F -- and it's sometimes desired to accept both upper-case and lower-case letters. There are again tricks to handling this, but doing it in a straight-forward fashion (compare each character to the limits of each run and decide which one it fits) is perfectly fine (and more general than other approaches). You can also even use a index op, where you simply find the character's index into "0123456789ABCDEF" -- inefficient but simple.

Resources