atoi function in C programming language K&R - c

I quite don't know what this loop does.
int atoi(char s[])
{
int i, n;
n = 0;
for (i = 0; s[i] >= '0' && s[i] <= '9'; ++i)
n = 10 * n + (s[i] - '0');
return n;
}
This part I don't get:
for (i = 0; s[i] >= '0' && s[i] <= '9'; ++i)
n = 10 * n + (s[i] - '0');
I get the whole for loop inside parentheses, and what s[i] - '0' does.
But I don't get what kind of operation is going on here --> n = 10 * n.
I don't know what n is representing and why is multiplying 10.
I know it's converting string of digits to numeric equivalent, but I just don't get the whole operation there.

But I don't get what kind of operation is going on here --> n = 10 * n
That's just how you build a number digit by digit. It's basically the same as it would work if you were writing a calculator. If I wrote a simple calculator, here's how it would handle the input 547:
Start with 0
5 ==> 0*10 + 5 = 5
4 ==> 5*10 + 4 = 54
7 ==> 54*10 + 7 = 547
Basically, atoi does, the exact same thing, but instead of reading each digit from button presses, it's reading them from a string. Each time you read a new digit, you do n *= 10 to make room for that next digit, which just gets directly added on the end.

n is the digits that has already been processed. For instance, for the string "123", first, the program gets digit 1, convert it to integer and store it in n, and then get the next digit 2, this is where n = 10 * n is useful, the previous 1 is multiplied by 10, and added to the next digit 2, the result is 12, and this is stored as the current n.
The same goes on, when processing 3, the previous stored 12 is multiplied by 10, results in 120 and added to 3, ended as 123 as result.

Related

We are given a number lets say m. We have to distribute the number into n parts

Lets says I have a number m = 9. I want to divide it into n=5 parts like given below:
As m>n, each part will get at least 1.
First give 1 to all 5 parts
part0: 1,
part1: 1,
part2: 1,
part3: 1,
part4: 1
Now for the remaining (9 - 5 = 4) divide again starting from 1st. final allocation looks like:
part0: 2
part1: 2
part2: 2
part3: 2
part4: 1
algo:
take an array arr[n]={0}.
x=0
while(m) {
arr[x]+=1;
m--;
x=(x+1)%n;
}
My question is I don't want to run this loop to divide n into m parts. Mathematically, how can I know the value allocated to a part directly. i.e part0: 2 for above example.
Integer division gets you the "base" size of all parts: 9 / 5 == 1.
Modulo gives you the remainder, 9 % 5 == 4. This means you should add 1 to the first 4 parts.
int partCount = 5;
int number = 9;
int base = number / partCount;
int remain = number % partCount;
for (int i=0; i<partCount; i++) {
part[i] = base;
if (i < remain) part[i]++;
}
The algorithm might be clearer if you use larger numbers. E.g. 31 in 7 parts:
31 / 7 == 4 - so we have 7 parts of 4 each, (== 28) plus the remainder:
31 % 7 == 3 - give the first 3 parts 1 more each to make 31 total.
for (i=0; i<n; i++) {
arr[i] = m/n + (m%n < i ? 1 : 0);
}

Atoi function in C?

int atoi(char* s)
{
int i,n;
n=0;
for (i=0; (s[i]>='0') && (s[i]<='9'); i++)
n = 10 * n + (s[i] - '0');
return n;
}
In this code what is s[i]-'0' doing? Can anyone please explain the detailed working of this function?
Have a look at the table in the link below-
http://www.asciitable.com/
The table is called ASCII Table and it is one of the character-encoding schemes used to represent characters in the binary world.
You can see the decimal numbers 0-9 are represented by numbers 48-57 in the ASCII table. All digits(0-9) are stored as characters.
If your computer stores 48 for decimal number 0, 49 for decimal number 1, 50 for decimal number 2 and so-on.
Then, to convert a ASCII number into decimal number, you just need to subtract 48 from ASCII number.
For example,
48 - 48 => 0
49 - 48 => 1
50 - 48 => 2
.. and so-on
'0' also represents 48. It is a character form of number 48. That's why, the equation n = 10 * n + (s[i] - '0'); has '0'.
In this code what is s[i]-'0' doing?
In C, each character like '0', 'A', '+', ' ' is assigned a numeric value or code. C requires that the codes for '0', '1', '2' ... '9' are sequential but does not specify their values.
When code performs the below test, it knows that s[i] has a value within codes '0' and '9'. Since these codes are sequential, the only values s[i] could have are '0', '1', '2' ... '9'.
(s[i]>='0') && (s[i]<='9')
By subtracting '0' from s[i], code obtains the difference:
`0`-'0' --> 0
`1`-'0' --> 1
`2`-'0' --> 2
...
`9`-'0' --> 9
Code has successfully translated the character code for an numeric character into a corresponding integer value.
In your function, s is a sequence of ASCII encoded characters: a string. Actually, the encoding does not matter as long as it has the characters 0 through 9 as a sequence. Let's say it has the value "123ABC", for this explanation.
n is the output number. At the start of the function it is initialized to zero.
In the first iteration of the loop we have
i=0
s[i] = '1' (which is encoded as 49, in ASCII)
n = 0
so the math is like this:
n = n * 10 + (s[i] - '0')
n = 0 * 10 + ('1' - '0')
n = '1' - '0'
And converting the character syntax to the ASCII encoding gives this:
n = 49 - 48
n = 1
In the next iteration we have:
i = 1
s[i] = '2' (ASCII 50)
n = 1
n = n * 10 + (s[i] - '0')
n = 1 * 10 + ('2' - '0')
n = 10 + ('2' - '0')
n = 10 + (50 - 48)
n = 10 + 2
n = 12
And, in the third iteration:
i = 2
s[i] = '3' (ASCII 51)
n = 12
n = n * 10 + (s[i] - '0')
n = 12 * 10 + ('3' - '0')
n = 120 + ('3' - '0')
n = 120 + (51 - 48)
n = 120 + 3
n = 123
And, in the final iteration s[i] = 'A' which is not in the range specified by the if statement, so the loop exits.
As you can see it has correctly converted the string "123" to the number 123.

Count alphabets in C using log functions(without math.h) and arrays

I'm facing a slight problem with one of my projects. I am supposed to write a c program to calculate each character present in the input/file. (It's supposed to be a basic program.) The constraints - I cannot use the math.h library to produce log functions and obtain an output in the format:
1
5 1 2 0 2 2 5 8 4 3 6 6 2 5 5 7 2 1 1 2
7 9 8 1 7 2 4 1 0 0 4 5 0 2 2 5 2 6 3 6 6 3 7 0 2 2
A B C D E F G H I J K L M N O P Q R S T U V W X Y Z
The program is supposed to count the number of occurrences of each alphabetic letter (case insensitive) in the stdin input stream and display a histogram.
As you can see, the output is formatted vertically with each line printing the base 10 number of the position of the character.
Now, this might seem silly, but what I have so far is this:
#include <stdio.h>
#include <ctype.h>
/*
int logBase10 (int num) {
method to calculate the log base 10 of num
}
*/
int main (int argc, char * argv[]) {
char alpha;
int count = 0;
int ascii[128] = {0};
while ( (alpha = getchar()) != EOF) {
count++;
ascii[(int)alpha]++;
alpha = getchar();
}
printf("Char \t Count \n");
printf("------------------------\n");
for (int i = 0; i < 127; i++) {
if(ascii[i] > 0) {
printf("%c \t %d \n", i, ascii[i]);
}
}
}
Which produces an output like this:
Char Count
------------------------
5
93
, 6
- 2
. 3
; 2
C 2
I 6
N 1
T 1
W 2
a 26
b 5
c 8
d 13
e 55
f 11
g 7
h 28
i 32
k 3
l 26
m 17
n 31
o 27
p 12
q 1
r 26
s 22
t 42
u 11
v 8
w 8
y 13
z 1
First off, my program is printing unwanted ascii characters (, ; - etc) and I am working on changing the print function to be more vertical, but I cannot figure out the log method at all. I know log(10) is 1 because 10^1 is 1, but I am having trouble figuring out how to use this to create the method itself. Also, for the extra characters, I tried using:
if(ascii[i] > 65 || ascii[i] < 90 || ascii[i] >= 97 || ascii[i] <= 122 ) {
printf("%c \t %d \n", i, ascii[i]);
}
to no avail. Trying that produced more gibberish characters instead.
Any help/feedback is appreciated.
Soul
The commenters have already pointed out issues with your code. Here's a version that counts only letters and prints vertical labels. It doesn't need <ctype.h> or <math.h>.
Each character hets a letter index which is a number from 0 to 25 for upper and lower case letters and −1 if the character isn't a letter. That reduces the array size to 26.
You could find out each digit with elaborate calculations, but the easiest way is to print the number to a string. snprintf does this for you. You can right-align the number with a field width. The maximum value for a typical int is about 2 billion, which has 10 digits. You should account for that, even if you had to pass in the whole Moby-Dick plus the Bible to get that many counts.
You can test whether you should start printing by assuming a width of ten digits first and checking whether the maximum count has ten digits, that is whether it is 1,000,000,000 or higher. Then divide that limit by 10 in each iteration.
Here's the code:
#include <stdio.h>
// return letter index or -1 for non-letter
int letter(int c)
{
if ('a' <= c && c <= 'z') return c - 'a';
if ('A' <= c && c <= 'Z') return c - 'A';
return -1;
}
int main(int argc, char * argv[])
{
int count[26] = {0}; // letter counts
char label[26][12]; // buffer for printing numbers
int limit = 1000000000; // smallest 10-digit number
int max = 0;
int i, j;
// read and count letters
while (1) {
int c = getchar();
if (c == EOF) break;
c = letter(c);
if (c >= 0) count[c]++;
}
// write auxiliary labels
for (i = 0; i < 26; i++) {
snprintf(label[i], sizeof(label[i]), "%10d", count[i]);
if (count[i] > max) max = count[i];
}
// print vertical labels
for (j = 0; j < 10; j++) {
if (max >= limit) {
for (i = 0; i < 26; i++) {
putchar(' ');
putchar(label[i][j]);
}
putchar('\n');
}
limit /= 10;
}
// print horizontal rule
for (i = 0; i < 26; i++) {
putchar('-');
putchar('-');
}
putchar('-');
putchar('\n');
// print letters
for (i = 0; i < 26; i++) {
putchar(' ');
putchar('A' + i);
}
putchar('\n');
return 0;
}
On your example, it produces:
1
5 1 2 0 2 2 5 8 4 3 6 6 2 5 5 7 2 1 1 2
7 9 8 1 7 2 4 1 0 0 4 5 0 2 2 5 2 6 3 6 6 3 7 0 2 2
-----------------------------------------------------
A B C D E F G H I J K L M N O P Q R S T U V W X Y Z
One easy way to figure out how many digits that you'll need is to use sprintf to convert the integer count to a string, and then use strlen to find out how many digits you have. For example:
char str[20] = {0}; // 20 digits should be enough for your case
for (i = 0; i < 128; i++) {
sprintf(str, "%d", ascii[i]);
num_digits = strlen(str);
printf("%d has %d digits\n", ascii[i], num_digits);
}
I didn't test the code, but it should be close.
Some pseudo code
Find max count
Find width of that count when printed w=sprintf(buf, "%d", mxcnt)
Loop w times (wi = 0 to w - 1)
for each non-zero count
form string sprintf(buf, "%*d", w, count[i])
print buf[wi] character
print space
print \n

Multiplication using fgets in C

I am trying to do some multiplication. I am asking users to enter 9 digits number and multiply each digit with. Lets say if user enters 123456789 then we will do this:
123456789
246824682
We will multiply user input with this code:
#include <stdio.h>
int main(void) {
char num[10];
int num1,num2,num3;
printf("Enter your num: ");
fgets(num,10,stdin);
num1 = num[1] * 2;
num2 = num[2] * 4;
num3 = num[3] * 6;
printf("%d %d %d", num1,num2,num3);
return 0;
}
When I run this this is what I get:
admin#matrix:~/cwork> ./lab2
Enter your num: 123
100 204 60admin#matrix:~/cwork>
Why am I getting 100 204 and 60
I though I would get : 2 8 18 OR 2818!
First, in the C programming language, arrays are indexed starting at 0. So you need to change the indexes from [1], [2], [3] to [0], [1], [2].
Second, each digit in the input is an ASCII character. So the character 2 is actually stored in your array as the number 50. That's why num[1] * 2 is 100.
The easiest way to convert the digits to the numbers you expect is to subtract '0' from each digit. Putting it all together, your code should look like this
num1 = (num[0] - '0') * 2;
num2 = (num[1] - '0') * 4;
num3 = (num[2] - '0') * 6;
When you read from stdin you get a char array.
So in your example with "123"
your array looks like this:
num[1] == '2' == 50 // 50 is the ascii code for '2'
num[2] == '3' == 51 // 51 is the ascii code for '3'
So of course you are getting 100, 204 for these numbers.
Also note that arrays start with 0, not with 1!

Don't understand this C loop

Can anyone explain to me how does this loop works? I understand that the first operator counts its remainder, the second counts its division result, but I can't understand how does it sum them using the loop? Here's the code:
// Calculate the sum of the digits of the number N.
int N, S, Z;
S = 0;
printf("Input N\n");
scanf("%d", &N);
while(N != 0) {
Z = N % 10;
N = N / 10;
S = S + Z;
}
printf("Sum = %d\n", S);
This while loop adds all the digit of your number referred in by N. It add's all the digit by taking remainder of number when divided by 10. And everytime, it eliminates the last digit of the number. So if your number is 326, it will work like:
326 != 0
Z = 6
N = 32
S = 6
32 != 0
Z = 2
N = 3
S = 8
3 != 0
Z = 3
N = 0
S = 11
0 == 0 come out of loop
print value of S i.e. 11
It's basically a sum of digits of an integer number.
Example:
input ==> 1234
output ==> 4+ 3+ 2 + 1 = 10
Code Break down:
Initialize S [sum] to 0.
Loop:
Z = N % 10; , store the remainder of N after %10 into Z.
N = N / 10; , divide the contents on N by 10 and store the result back in N.
S = S + Z;, sum the content of S with the value in Z.
after that, check the modified value of N is 0 or not. If not, continue [1,2,3..)
Suggestion:
Always check the success of scanf("%d", &N);. If by any chance, scanf() fails, your code is trying to access uninitialized variable N, which may very well lead to undefined behaviour.
The loop will execute until the n value become zero. For example
N=123
Then the first time values of the variables is
Z:3 : N:12 : S:3
Second time
Z:2 : N:1 : S:5
Third time
Z:1 : N:0 : S:6
Finally the answer of S will be 3+2+1=6.
Let's for a example take 657:
Z = N % 10; // This line will store 7 in Z
N = N / 10; // this line will convert N to 65
S = S + Z; // and finally this line will add 0+7

Resources