I don't understand itoa() in K&R book - c

I am reading K&R; so far I'm doing well with it, but there is something in function itoa() which I don't understand. Here in itoa() they say they reverse the numbers themselves. For example 10 is 01 (they reverse the string):
void itoa(int n, char s[])
{
int i, sign;
if ((sign = n) < 0) /* record sign */
n = -n; /* make n positive */
i = 0;
do { /* generate digits in reverse order */
s[i++] = n % 10 + '0'; /* get next digit */
} while ((n /= 10) > 0); /* delete it */
if (sign < 0)
s[i++] = '-';
s[i] = '\0';
reverse(s);
return;
}
I don't understand how it reversed the number. Even though we are just doing n % 10 + '0' then its the following digit which 10 then 1 gets deleted then it goes to 0 right ? Or I don't get its logic ?

In the do-while loop, it is pulling the numbers off from behind (the least significant digit first). So, if you had the number -123456789, it processes the 9, then the 8, then the 7, etc.
So, when it hits the null-terminator (3rd to last line), you would have "987654321-", which is then reversed.

n % 10 gives 0 for n = 10, so after the loop, the string s contains 01.
The call to reverse() fixes this.

The algorithm determines the digits from least to most significant order. Because the total number of digits that will be generated is not known in advance, the correct position cannot be determined as they are generated - the least significant digit will be at the end, but the 'end' is not known. So they are buffered in the order they are calculated (reverse) and then the whole string is reversed to correct the ordering.
One way of avoiding this is to determine the length in advance:
decimal_digits = (int)log10( n ) + 1 ;
but on devices without an FPU (and some with very simple FPUs) that is likely to be a heavier task than string reversal.

Related

I don't know what I'm doing wrong with this Array

I'm trying to separate the numbers of a sequence, and store them all in an array.
For what the little I have seen of C, I am doing nothing wrong, and the program compiles perfectly, but the moment it goes to print the numbers, it just doesn't work.
The explanation of what I'm trying to do is in the end.
long int number;
do
{
number = get_long("number:\n");
}
while (number<1 || number>9999999999999999);
int numbers[16], n;
//We separate the numbers, from right to left
for (long int I=10; I>100000000000000000; I*=10)
{
for (long int J=1; J>100000000000000000; J*=10)
{
for (n=0; n>16; n++)
{
numbers[n]=(number%I)/J;
}
}
}
printf("%i\n", numbers[1]);
It is supposed to accept numbers of 1 digit up until 16 digits, and separate each digit.
For example, if we had 16, it would separate 1 and 6 into two digits, making the 6 the first digit, and the 1 the second, so it would start counting from right to left. It's supposed to store each digit in an array of 16 spaces. Then I would just print the second digit, just to make sure it does work, but when I run it, it just gives me 0; meaning it doesn't work, but I see no problem with it.
It probably is that I'm either too inexperienced, or I don't have the necessary knowledge, to be able to see the problem in the code.
You have incorrect loop termination checks, so the loops are never entered.
After reversing > to <, you end up evaluating the body of the inner loop 16*16*16 = 4096 times even though there are only 16 digits. There should only be one loop of 16 iterations.
A long int is not is only guaranteed to support numbers up to 2,147,483,647. Instead, use one of long long int, int_least64_t or int64_t, or one of their unsigned counterparts.
You were attempting to write the following:
uint64_t mod = 10; // Formerly named I
uint64_t div = 1; // Formerly named J
for (int n=0; n<16; ++n) {
numbers[n] = ( number % mod ) / div;
mod *= 10;
div *= 10;
}
Demo
But that's a bit more complicated than needed. Let's swap the order of the division and modulus.
uint64_t div = 1;
for (int n=0; n<16; ++n) {
numbers[n] = ( number / div ) % 10;
div *= 10;
}
Demo
Finally, we can simplify a bit more if we don't mind clobbering number in the process.
for (int n=0; n<16; ++n) {
numbers[n] = number % 10;
number /= 10;
}
Demo
All of your for loops are using operator> when they should be using operator< instead. Thus the loop conditions are always false (10 is not > than 100000000000000000, 1 is not > than 100000000000000000, 0 is not > than 16), so the loops don't get entered at all, and thus numbers[] is left unfilled.
Fixing that, you still have a logic problem. Think of what the result of (number%I)/J is when number is 16 and I and J are large values. The result of operator/ is typically 0! On some loop iterations, numbers[] gets populated with correct values. But other iterations will then overwrite numbers[] with 0s. Once all of the loops are finished, only the 0s are left.
This Online Demo demonstrates this in action.
If using a long variable, the value ranges are: -2147483648 to 2147483647 (in most C implementations, as noted by #Eric P in comments)
So the expression while (number<1 || number>9999999999999999); (and similar) do not make sense. As a number, number will never approach 9999999999999999. Same for expression: ...J>100000000000000000; J*=10). (and its really moot at this point, but > should be <)
Consider using a string approach:
Using a null terminated char array (C string) to hold initial value, the essential steps are pretty straight forward and could include the following:
char number[17];//room for 16 characters + null terminator
scanf("%16s", number);//string comprised of maximum of 16 digits
len = strlen(number);
int num_array[len];//using VLA
memset(num_array, 0, sizeof num_array);//zero array
for(int i = 0;i < len; i++)
{
if(number[i] < '0' || number[i] > '9') break;//qualify input. Break if non-numeric
num_array = number[i] - '0';
}

is there a way to use Arrays in this C problem?

I am doing this problem:
"We have a huge decimal number N. Write a program to determine the followings:
The number of digits in N.
Is N an even number?
The number of zeros in it.
Is N a multiple of 11? Note that we can determine if N is a multiple of 11 by checking the difference between the sum of the odd positioned digits and the sum of the even positioned digits. For example, 82375 is not a multiple of 11 because the sum of the even positioned digits is 2 + 7 = 9, and the sum of the odd positioned digits is 8 + 3 + 5 = 16, and the difference between 9 and 16 is 7, which is not a multiple of 11.
We will give you the number one digit per line. For example, if you get digits ‘1’, ‘2’, ‘3’, ’4’, ‘0’ in order, then the number is 12340. The number will not start with 0.
Input Format
The input has several lines. Each line has a digit. EOF indicates the end of input.
Output Format
Output the four answers above line by line. If the number is even output a 1; otherwise a 0. If the number is a multiple of 11 output a 1; otherwise output a 0.
Subtask
10 points: you can store the decimal number in an integer without overflow
10 points: the number of digits is no more than 32768, so you can store digits in an array
80 points: you will get MLE if you use array"
my code is:
#include <stdio.h>
#include <stdbool.h>
int digit(long n);
int is_even(int n);
int count_zeros(long n);
int is_multiple(long n);
int main() {
int digits = 0;
long x;
scanf("%ld", &x);
digit(x);
int even = is_even(x);
printf("%d\n", even);
printf("%ld\n",count_zeros(x));
printf("%ld\n", is_multiple(x));
}
int digit(long n)
{
int digits = 0;
while (n > 0) {
n /= 10;
digits++;
}
printf("%ld\n", digits);
}
int is_even(int n)
{
if (n % 2 == 0)
return true;
else
return false;
}
int count_zeros(long n)
{
int count = 0;
while (n > 0) {
n /= 10;
if (n %10 == 0)
count++;
}
return count;
}
int is_multiple(long n)
{
if (n % 11 == 0) {
return true;
}
else
return false;
}
Basically i dont know how to meet the problem's requirement, so I made a simpler version of the problem. Any clue on how to do this?
If you comment on this, please be nice, I am a beginner and people was rude in the past,if you have nothing important to say, do not be mean/do not comment.
Well, the first problem with your current version is it only reads one integer. However problem states that each digit is on a separate line. The first approach may be to just replace that scanf with a loop and keeping multiplying by 10 and accumulating until end of file. Then the rest of the program would work fine.
A more advanced approach will be to use an array to store the digits. An integer can hold a very limited number of digits whereas you are only bounded with the size of available memory using array.
So in the reading loop rather than storing digits in an integer, you can store digits in an array (which could be fixed size because an upper limit is given). But for the rest of the program you should change the calculation to use digits in the array instead of the regular integer arithmetic.

How to store 100 digit number in C using strings

My problem is that i dont know what this functions do, thats program
from my teacher(not whole program just functions). Just wanna ask you what this functions do, mainly why
i store my number from right to left at string? thanks
#include<stdio.h>
#include<string.h>
#define MAX 1000
void str_to_num(char *str, char *number, int *dlzka)
{
int i;
for(i=0; i < MAX; i++)
number[i] = 0;
*dlzka = strlen(str);
for(i = 0; i < *dlzka; i++)
cis[(*dlzka) - 1 - i] = str[i] - '0';
}
void plus(char *cislo, int *d1, char *cis2, int d2)
{
int i; prenos = 0;
if(*d1 < d2)
*d1 = d2;
for(i = 0; i < *d1; i++)
{
pom = number[i] + number[i];
pom += prenos;
number[i] = pom % 10;
prenos = pom / 10;
}
}
Here is the lesson your teacher should be teaching:
There is a difference between the numerical value of 1, and the computer code (ASCII for example) that is used to represent character 1 displayed on the screen or typed on the keyboard.
Every time you see 1 on the screen, your computer sees 49 in memory.
0 is 48, 2 is 50 and so on.
Conveniently, all digit characters are arranged in a sequence from 0 to 9, so to convert their character codes to their numeric values all you have to do is subtract the character code of zero to get the digit position in the sequence.
For example: 49 - 48 = 1 --> '1' - '0' = 1
And this is how the first function, str_to_num works.
C language does not provide a variable large enough to work with 100 digit numbers, so you need to sum them up one digit at a time.
The second function has completely wrong variable names, but it is still pretty obvious what it is trying to do:
It sums up two single digit numbers, then stores the ones part of the result in an array and the tenth (if sum is > 9) in a helper variable.
As already suggested in the comments, this is how you sum up numbers manually on a page one digit at a time.
I don't know what prenos means in your language, but in English this variable should be called carry and it keeps the overflowing tens digit for the next round.
There is however something missing from the sum function: if the sum of the last (leftmost) two digits is more than 9, the extra 1 will be lost, and the result will be wrong.
Check the original code your teacher gave you - either you copied it wrong, or he is giving a bad example.

How should I generate the n-th digit of this sequence in logarithmic time complexity?

I have the following problem:
The point (a) was easy, here is my solution:
#include <stdio.h>
#include <string.h>
#define MAX_DIGITS 1000000
char conjugateDigit(char digit)
{
if(digit == '1')
return '2';
else
return '1';
}
void conjugateChunk(char* chunk, char* result, int size)
{
int i = 0;
for(; i < size; ++i)
{
result[i] = conjugateDigit(chunk[i]);
}
result[i] = '\0';
}
void displaySequence(int n)
{
// +1 for '\0'
char result[MAX_DIGITS + 1];
// In this variable I store temporally the conjugates at each iteration.
// Since every component of the sequence is 1/4 the size of the sequence
// the length of `tmp` will be MAX_DIGITS / 4 + the string terminator.
char tmp[(MAX_DIGITS / 4) + 1];
// There I assing the basic value to the sequence
strcpy(result, "1221");
// The initial value of k will be 4, since the base sequence has ethe length
// 4. We can see that at each step the size of the sequence 4 times bigger
// than the previous one.
for(int k = 4; k < n; k *= 4)
{
// We conjugate the first part of the sequence.
conjugateChunk(result, tmp, k);
// We will concatenate the conjugate 2 time to the original sequence
strcat(result, tmp);
strcat(result, tmp);
// Now we conjugate the conjugate in order to get the first part.
conjugateChunk(tmp, tmp, k);
strcat(result, tmp);
}
for(int i = 0; i < n; ++i)
{
printf("%c", result[i]);
}
printf("\n");
}
int main()
{
int n;
printf("Insert n: ");
scanf("%d", &n);
printf("The result is: ");
displaySequence(n);
return 0;
}
But for the point b I have to generate the n-th digit in logarithmic time. I have no idea how to do it. I have tried to find a mathematical property of that sequence, but I failed. Can you help me please? It is not the solution itself that really matters, but how do you tackle this kind of problems in a short amount of time.
This problem was given last year (in 2014) at the admission exam at the Faculty of Mathematics and Computer Science at the University of Bucharest.
Suppose you define d_ij as the value of the ith digit in s_j.
Note that for a fixed i, d_ij is defined only for large enough values of j (at first, s_j is not large enough).
Now you should be able to prove to yourself the two following things:
once d_ij is defined for some j, it will never change as j increases (hint: induction).
For a fixed i, d_ij is defined for j logarithmic in i (hint: how does the length of s_j increase as a function of j?).
Combining this with the first item, which you solved, should give you the result along with the complexity proof.
There is a simple programming solution, the key is to use recursion.
Firstly determine the minimal k that the length of s_k is more than n, so that n-th digit exists in s_k. According to a definition, s_k can be split into 4 equal-length parts. You can easily determine into which part the n-th symbol falls, and what is the number of this n-th symbol within that part --- say that n-th symbol in the whole string is n'-th within this part. This part is either s_{k-1}, either inv(s_{k-1}). In any case you recursively determine what is n'-th symbol within that s_{k-1}, and then, if needed, invert it.
The digits up to 4^k are used to determine the digts up to 4^(k+1). This suggests writing n in base 4.
Consider the binary expansion of n where we pair digits together, or equivalently the base 4 expansion where we write 0=(00), 1=(01), 2=(10), and 3=(11).
Let f(n) = +1 if the nth digit is 1, and -1 if the nth digit is 2, where the sequence starts at index 0 so f(0)=1, f(1)=-1, f(2)-1, f(3)=1. This index is one lower than the index starting from 1 used to compute the examples in the question. The 0-based nth digit is (3-f(n))/2. If you start the indices at 1, the nth digit is (3-f(n-1))/2.
f((00)n) = f(n).
f((01)n) = -f(n).
f((10)n) = -f(n).
f((11)n) = f(n).
You can use these to compute f recursively, but since it is a back-recursion you might as well compute f iteratively. f(n) is (-1)^(binary weight of n) = (-1)^(sum of the binary digits of n).
See the Thue-Morse sequence.

I don't understand atoi function in K&R C book?

#include <stdio.h>
#include <string.h>
int main(void)
{
char s[]= "9";
printf("atoi = %d",atoi(s));
system("pause");
return 0;
}
int atoi(char s[])
{
int i=0,n=0;
for(i;s[i]>='0' && s[i]<='9';i++)
n=10*n + (s[i]-'0');
return n;
}
In above program it gave me result 9 as per program it should print ascii value for 9
and I don't understand what this for loop does.
for(i;s[i]>='0' && s[i]<='9';i++)
n = 10*n + (s[i]-'0');
Lets break this down:
for (i;
This creates a for loop, with the loop variable i. This is not necessary, but more of a coding style.
s[i] >= '0' && s[i] <= '9'
This checks to make sure that the character at that index is inside the range for a decimal character (0 - 9), and if it is not, it exits the loop, then returns the number.
i++
After the loop runs, this increases the index you are checking in the string by one.
n = 10 * n
This adds an extra digit to 'n' by multiplying by 10, because you know that if you have one more character in your number, it must be multiplied by ten (say I start parsing 100, I read the first two strings, and have 10, there is one more character, so I multiply by ten to get 100.
+ (s[i]-'0');
This adds the next digit to 'n', the result, which is determined by subtracting the character at the current index by '0', which, when in the range of 0 - 9, returns the integer for that number (if this confuses you, take a look at an ASCII Chart.
Hopefully this helped you understand.
this converts string representation to number like "329" to 329
It takes 3 first then 3*10+2=32
then 32*10 + 9 =329
for(i;s[i]>='0' && s[i]<='9';i++) /* loop over just the digits, in L->R order */
n = 10*n + (s[i]-'0'); /* Take value so far, "shift" a 10's place left,
and add in value of latest digit
(diff between ASCII of digit & ASCII of zero) */

Resources