Storing integers in char array and adding - c++

I have come to know that one can store digits from 0-255 in char data type. So, I tried the following code:
#include <stdio.h>
int main()
{
unsigned char num[4];
int sum=0;
int i=0;
printf("Enter Four Digit Number\n");
while(i<4)
{
scanf("%1d",&num[i]);
i++;
}
sum=(int)num[0]+(int)num[1]+(int)num[2]+(int)num[3];
printf("Sum of digits: %d",sum);
return 0;
}
which seems to run correctly but as soon as I put the following code in while loop, the value of i changes to zero every time the loop reiterates and code breaks:
sum=sum+(int)(num[i]); i++;
I'm using code::blocks with MinGW compiler.

Be VERY VERY careful when you use character types to store numbers. The range of a signed char can vary depending on your compiler, and the operating system. On most, the minimum value is -128 and the maximum value is 127. On others it can differ. This can become problematic when you expect the range to be from 0-255. If you want to use a char to store numbers, use unsigned char, as it's range is 0-255.
Because the numeric representations of a character (signed, or unsigned) are not garunteed, I usually approach the problem by writing a function that uses an array to assign, and look up, the numeric values. (but, I almost never do this, it's easier to use an integer...)

if you want add the integer value into the particular index
char a[10];
int i=9;
a[2]=boost::lexical_cast<char>(i)
found this is the best way to convert char into int and vice-versa.

This works fine for me.
while(i < 4){
scanf("%1d", &num[i]);
sum += (int)(num[i++]);
}

Related

How does "narrowing" work when converting int to char in C++?

I'm a beginner with C++ and had a question about conversions. When converting int to char values, what happens when 127 is exceeded on the ASCII table?
For example,
using namespace std;
int main()
{
double d = 0;
while (cin>>d){
int i = d;
char c = i;
int i2 = c;
cout<<"d=="<<d<<endl;
cout<<"i=="<<i<<endl;
cout<<"c=="<<c<<endl;
cout<<"i2=="<<i2<<endl;
cout<<"char:("<<c<<")"<<endl;
}
}
Now if the use inputs 150, i becomes 150 as i = d, c becomes û as c = i, which means to me that int 150 = char û
BUT when the int i2 is outputted on the screen, given that int i2 converts char c back into an integer, i2 == 106
My assumption is that int i2 would also be 150.
I'd appreciate if someone could explain this to me as I'm struggling to grasp the concept. I've read that since char can hold 1 byte of information whereas int can hold 4 bytes of information, the value is "narrowed". I'm not entirely sure what that means however!
How does “narrowing” work when converting int to char in C++?
The width of an integer type is roughly the number of bytes (or bits) it contains. So, one type is narrower than another if it has fewer bytes (or bits).
Consider a physical manifestation of int - it's an index card with eight boxes marked on it, and we can write one digit in each box. Maybe it's going to be read by one of those automated optical systems, but anyway we're not allowed to squeeze more digits on there or write outside the boxes.
Now, we have an equivalent card representing a char - it has two boxes marked on it.
The char card can be physically narrower as well, to really hammer home the analogy, but the important thing is that you can only write two digits.
So, in base 10, an int card can store 0-99,999,999, and a char can store 0-99.
Now, I give you an int card with the number 123 written on it, and ask you to copy the value onto a char card. What can you do? You can discard the hundreds digit that doesn't fit, and just write 23. Or I guess you can just throw up your hands in horror and refuse. Typically we want computers to do the former.
This is a narrowing conversion. The char is physically too small (narrow) to fit all the information an int can contain.
Finally, to describe the actual int and char types, we can either use binary (in which case we can only use digits 0 and 1, and the int card has thirty-two boxes while the char card has eight), or we can leave our index cards the same size if we write our digits in base 16 instead of base 10.
There is a further complication in that int is signed, so we also need to represent negative values too in our fixed number of digits. The char may be signed or unsigned - it's implementation dependent. If you're interested, you can look up two's complement, which is the most common way of storing signed values, but in general half of the values you can store, are going to be negative.
So roughly, the two ways a narrowing conversion can do the wrong thing are:
the narrower type just doesn't have enough digits, so some are cut off
the narrower type can fit all the digits, but is signed, and that particular pattern represents a negative number in the narrow type (assuming it was positive in the wide one)

Is it possible to return an integer to the main function from a unsigned char data type function?

I have this unsigned char sumBinaryFigure function that calculates the sum of the digits of the binary representation of an unsigned long long number. When I call this function from the main function, for an unsigned long long it should return a integer(or another numeric data type) although the data type of the function is unsigned char. Is it possible? I tried a function overloading and it didn't work. If it sounds absurd, it's not my fault.
unsigned char sumBinaryFigure(unsigned long long number)
{
unsigned int S = 0;
while (number)
{
S += number % 2;
number /= 2;
}
return S;
}
When I call this function from the main function, for an unsigned long long it should return a integer although the data type of the function is unsigned char. Is it possible?
Yes. The question is not absurd, C types are just confusing. unsigned char and int both represent integers.
Your code is correct.
unsigned char is a 1-byte datatype. It can be used to represent a letter, or it can be used to represent a number.
The following statements are equivalent.
unsigned char ch = 'A';
unsigned char ch = 65;
Whether you use unsigned char as a character or integer, the machine does not care.
char does not necessarily contain a character. It also represents small numbers
The posted implementation of sumBinaryFigure returns a number in the range of 0-255, nothing wrong with that. Because a long long is almost certainly less than 256 bits, you don't need to worry about unsigned char not being large enough.
If I can suggest one change to your program in order to make it less confusing, change this line
unsigned int S = 0;
to this...
unsigned char S = 0;
Addendum
Just to be clear, consider the following code.
int main (void) {
char ch_num = 65; // ch_num is the byte 0100 0001
char ch_char = 'A'; // ch_char is the byte 0100 0001
printf ("%d\n", ch_num); // Prints 65
printf ("%d\n", ch_char); // Prints 65
printf ("%c\n", ch_num); // Prints A
printf ("%c\n", ch_char); // Prints A
}
A char is a byte. It's a sequence of bits with no meaning except what we impose on it.
That byte can be interpreted as either a number or character, but that decision is up to the programmer. The %c format specifier says "interpret this as a character. The %d format specifier says "interpret this as a number".
Whether it's an integer or character is decided by the output function, not the data type.
unsigned char can be converted to int without narrowing on all platforms that I can think of. You don't need to overload anything, just assign the result of the function to an int variable:
int popcnt = sumBinaryFigure(1023);
In fact, taking the function semantics into account, there's no way the result value will not fit into an int, which is guaranteed to be at least 16-bit, which means the minimal numeric_limits<int>::max() value is 32767. You'd have to have a datatype capable of storing over 32767 binary digits for this to be even remotely possible (int on most platforms is 32-bit)

C++ string.length() Strange Behavior

I just came across an extremely strange problem. The function I have is simply:
int strStr(string haystack, string needle) {
for(int i=0; i<=(haystack.length()-needle.length()); i++){
cout<<"i "<<i<<endl;
}
return 0;
}
Then if I call strStr("", "a"), although haystack.length()-needle.length()=-1, this will not return 0, you can try it yourself...
This is because .length() (and .size()) return size_t, which is an unsigned int. You think you get a negative number, when in fact it underflows back to the maximum value for size_t (On my machine, this is 18446744073709551615). This means your for loop will loop through all the possible values of size_t, instead of just exiting immediately like you expect.
To get the result you want, you can explicitly convert the sizes to ints, rather than unsigned ints (See aslgs answer), although this may fail for strings with sufficient length (Enough to over/under flow a standard int)
Edit:
Two solutions from the comments below:
(Nir Friedman) Instead of using int as in aslg's answer, include the header and use an int64_t, which will avoid the problem mentioned above.
(rici) Turn your for loop into for(int i = 0;needle.length() + i <= haystack.length();i ++){, which avoid the problem all together by rearranging the equation to avoid the subtraction all together.
(haystack.length()-needle.length())
length returns a size_t, in other words an unsigned int. Given the size of your strings, 0 and 1 respectively, when you calculate the difference it underflows and becomes the maximum possible value for an unsigned int. (Which is approximately 4.2 billions for a storage of 4 bytes, but could be a different value)
i<=(haystack.length()-needle.length())
The indexer i is converted by the compiler into an unsigned int to match the type. So you're gonna have to wait until i is greater than the max possible value for an unsigned int. It's not going to stop.
Solution:
You have to convert the result of each method to int, like so,
i <= ( (int)haystack.length() - (int)needle.length() )

Large Number Issues in C++

I'm working on a relatively simple problem based around adding all the primes under a certain value together. I've written a program that should accomplish this task. I am using long type variables. As I get up into higher numbers (~200/300k), the variable I am using to track the sum becomes negative despite the fact that no negative values are being added to it (based on my knowledge and some testing I've done). Is there some issue with the data type or I am missing something.
My code is below (in C++) [Vector is basically a dynamic array in case people are wondering]:
bool checkPrime(int number, vector<long> & primes, int numberOfPrimes) {
for (int i=0; i<numberOfPrimes-1; i++) {
if(number%primes[i]==0) return false;
}
return true;
}
long solveProblem10(int maxNumber) {
long sumOfPrimes=0;
vector<long> primes;
primes.resize(1);
int numberOfPrimes=0;
for (int i=2; i<maxNumber; i++) {
if(checkPrime(i, primes, numberOfPrimes)) {
sumOfPrimes=sumOfPrimes+i;
primes[numberOfPrimes]=long(i);
numberOfPrimes++;
primes.resize(numberOfPrimes+1);
}
}
return sumOfPrimes;
}
Integers represent values use two's complement which means that the highest order bit represents the sign. When you add the number up high enough, the highest bit is set (an integer overflow) and the number becomes negative.
You can resolve this by using an unsigned long (32-bit, and may still overflow with the values you're summing) or by using an unsigned long long (which is 64 bit).
the variable I am using to track the sum becomes negative despite the fact that no negative values are being added to it (based on my knowledge and some testing I've done)
longs are signed integers. In C++ and other lower-level languages, integer types have a fixed size. When you add past their maximum they will overflow and wrap-around to negative numbers. This is due to the behavior of how twos complement works.
check valid integer values: Variables. Data Types.
you're using signed long, which is usually 32 bit, which means -2kkk - 2kkk, you can either use unsigned long, which is 0-4kkk, or use 64 bit (un)signed long long
if you need values bigger 2^64 (unsigned long long), you will need to use bignum math
long is probably only 32 bits on your system - use uint64_t for the sum - this gives you a guaranteed 64 bit unsigned integer.
#include <cstdint>
uint64_t sumOfPrimes=0;
You can include header <cstdint> and use type std::uintmax_t instead of long.

Finding the Sum of 2D vector

Having some trouble finding the sum of a 2D vector. Does this look ok?
int sumOfElements(vector<iniMatrix> &theBlocks)
{
int theSum = 0;
for(unsigned i=0; (i < theBlocks.size()); i++)
{
for(unsigned j=0; (j < theBlocks[i].size()); j++)
{
theSum +=theBlocks[i][j];
}
}
return theSum;
}
It returns a negative number, however, it should return a positive number..
Hope someone can help :)
The code looks proper in an abstract sense, but you may be overflowing theSum. You can try making theSum type double to see what value you get to help sort out the proper integral type to use for it.
double sumOfElements(vector<iniMatrix> &theBlocks)
{
double theSum = 0;
/* ... */
return theSum;
}
When you observe the returned value, you can see if it would fit in an int or if you need to use a wider long or long long type.
If all the values in the matrix are positive, you should consider using one of the unsigned integral types. which would double your range of allowed values.
The problem is obviously the int exceeds its boundary (like others said)
For signed data types it becomes negative when overflow, and for unsigned datatypes it starts from zero again after overflow.
If you want to detect overflow pragmatically, you can paste these lines instead of the additional line.
if( theSum > int(theSum + theBlocks[i][j]) )
//print error message, throw exception, break, ...
break;
else
theSum += theBlocks[i][j];
For more generic solution to work with more data types and more operations than addition, check this: How to detect integer overflow?
A solution would be using unsigned long long and if it exceeds its boundary too, you need to use third party libraries for big integers.
Like Mokhtar Ashour says, it's may be that the variable theSum overflows. Try making it either unsigned if no numbers are negative, or change the type from int (which is 32 bits) to long long (which is 64 bits).
I think it may be int overflow problem. to make sure, you may insert a condition after the inner loop finishes to see if your result exceeds the int range.
if(result>sizeof(int))
cout<<"hitting boundaries";
a better way to test if you exceed the int boundaries is to print the result after the inner loop ends and notice the result.
.if so, just use a bigger data type.