the following two programs are supposed to produce all three digit combinations of 1, 2, 3 (with repetition). They are identical in every way, other that where the loop counters are being initialized
#include <stdio.h>
int main(void)
{
short i, j, k;
i = j = k = 1;
for (; i <= 3; i++) {
for (; j <= 3; j++) {
for (; k <= 3; k++)
fprintf(stdout, "%hi %hi %hi\n", i, j, k);
}
}
return 0;
}
...This one where the counters for the three loops are being initialized outside them doesn't produce the desired output. It prints.
1 1 1
1 1 2
1 1 3
The second one...
#include <stdio.h>
int main(void)
{
short i, j, k;
for (i = 1; i <= 3; i++) {
for (j = 1; j <= 3; j++) {
for (k = 1; k <= 3; k++)
fprintf(stdout, "%hi %hi %hi\n", i, j, k);
}
}
return 0;
}
...where the counters are being initialized within each loop, produces the desired output
1 1 1
1 1 2
1 1 3
1 2 1
1 2 2
1 2 3
1 3 1
1 3 2
1 3 3
2 1 1
2 1 2
2 1 3
2 2 1
2 2 2
2 2 3
2 3 1
2 3 2
2 3 3
3 1 1
3 1 2
3 1 3
3 2 1
3 2 2
3 2 3
3 3 1
3 3 2
3 3 3
Read in a book that a for loop can be written in several forms--all of which are identical--and that the counter can be initialized, incremented, tested either inside or outside the for statement. Then why the different behavior here?
Because you don't initialize the variables i, j, k inside the loop but define them in the outer scope, their values remain saved.
In particular k remains 4, after the first loop finishes to run, then the condition k<=3 is always false and the print statement is never reached.
To write the code in the equivalent way to your book meant is that way:
#include <stdio.h>
int main(void)
{
short i, j, k;
i = 1;
for (; i <= 3; i++) {
j = 1;
for (; j <= 3; j++) {
k = 1;
for (; k <= 3; k++)
fprintf(stdout, "%hi %hi %hi\n", i, j, k);
}
}
return 0;
}
In the second one, the variables j and k are reinitialised to 1 each time the for loop is encountered.
In the first one, they are always just left with the value that they had - which means that the second time round (when i == 2 or 3), j is left at 4 from the first time round, which immediately fails the j <= 3 condition.
it's not about how you initialize the for loop, but the fact that each time that you start the for loop you don't initialize it.
for (; i <= 3; i++) {
for (; j <= 3; j++) {
for (; k <= 3; k++)
so for the first time it's fine since the values are correct, but after the 2nd and 3rd for loop finished their iterations and the first for loop reached the 2nd index the other for loops are not being initialized so their values remain 4 and the condition isn't being met, so the loops stop there.
you still need to use the initialization inside the nested for loops regardless to fix the issue.
If you initialize your variables just once, outside the for loops, then their values will never get re-initialized in the nested loops (something you need in order to generate every combination starting with 1xx, 2xx and 3xx).
In the case of the outside initialization:
After you've generated all the 11x combinations, your k variable will have the value 4, regardless of what the enclosing loops do.
So when either j or i increments to 2 and 3, your k will already be 4, hence the innermost for loop will not execute anymore.
Needless to say, the second variant of your code, re-initializes k and j every time i increments, which will then make your code reach the printf every time like you intended.
Related
I am getting this error message while trying to run the following program "relational comparison result unused".
#include <stdio.h>
int main(void)
{
int i, j;
for(i = 0, j = 0; i < 10, j < 3; i++, j++)
{
printf("%i %i\n",i, j);
}
}
I am expecting a result
0 0
1 1
2 2
After adding two conditions
It's not two conditions, you probably need i < 10 && j < 3.
relational comparison result unused
As user3386109 mentioned, it's because the compiler discards the result of i < 10 caused by the comma, so you need to change it to i < 10 && j < 3.
I am expecting a result 0 0, 1 1, 2 2
Actually, I'm getting this result.
0 0
1 1
2 2
First of all, this is a school assignment, so I can't use the <math.h> library as a handicap.
So as the title suggests, I tried to write a function that gets a sequence of positive numbers for its input, then returns the number of which the sequence would continue. For example, if the sequence is 3 1 1 1 1 3 3 3 1 1 1 3 3 3 1 1 1 1 then it would return a 3 because that's what the next number would be. The sequence of numbers always ends with -1, however, -1 is not part of the sequence, it merely marks its end.
Here's the function:
#include <stdio.h>
int predict(int seq[]) {
int i, j;
for (i = 0; seq[i] != -1; i++)
;
int seqLength = i;
int rep[i+1];
for (j = 0; j < i + 1; j++)
rep[j] = -1;
i = 0;
j = 1;
while (seq[i] != -1) {
if (rep[0] == seq[i]) {
for (j = 1; seq[i + j] != -1; j++) {
if (rep[j] == seq[i + j]) {
j++;
} else {
rep[i] = seq[i];
j = 1;
break;
}
}
i++;
} else {
rep[i] = seq[i];
i++;
}
}
for (i = 0; rep[i] != -1; i++)
;
int repLength = i;
return seq[seqLength % repLength];
}
int main() {
int seq[20] = {1, 2, 1, 1, 2, 1, 2, 3, 1, 2, 1, 1, 2, 1, 2, -1}; /*or any other positive numbers as long as it ends with -1*/
printf("%d\n",predict(seq));
return 0;
}
The seq (short for sequence) is the sequence of numbers the function gets as the input.
seqLength is the number of how many numbers the seq has.
The rep (short for repeat) is the part of the sequence which repeats itself.
repLength is the number of how many numbers the rep has.
The function works for all three test cases which I know, for example:
For 3 1 1 1 1 3 3 3 1 1 1 3 3 3 1 1 1 1 it returns 3.
For 1 2 3 1 2 3 4 1 2 3 1 2 3 4 1 2 3 it returns 1.
For 1 2 1 1 2 1 2 3 1 2 1 1 2 1 2 it returns 3.
However, when I upload it to the school system that tests and appraises my function, it tests for an additional two test cases, which are wrong. The problem is, that I don't know the input sequence for those additional two test cases and therefore I don't know what to change in order for my functions to work for all test cases. Can someone see an error in my work and have an idea of what to change in order for my function to work for any repeating number sequences, even for unknown ones?
There is a corner case for which your algorithm does not work: if the repeated sequence has length seqLength, you will not find -1 in the rep array because it was defined with a length of seqLength and the end of list marker was never copied there. Hence the last loop will run past the end of rep and cause undefined behavior.
I'm afraid there are other problems, let's try and simplify the code:
It would be safer to compare the index values to seqLength instead of testing for -1, which by the way you did not document as the end of list marker.
Furthermore, it seems superfluous to copy the sequence into a rep array as this array would always contain an initial portion of seq.
The problems seems to boil down to finding the length of the repeated pattern.
Here is a simplified version, with seqLength passed as an argument:
int predict(int seq[], int seqLength) {
/* find the mininum value of repLength such that the sequence is
a repeated pattern of length repLength */
int i, repLength;
for (repLength = 1; repLength < seqLength; replength++) {
for (i = 0; i < seqLength; i++) {
if (seq[i] != seq[i % repLength])
break;
}
if (i == seqLength) {
/* we found the pattern length */
break;
}
}
return seq[seqLength % repLength];
}
I want to generate all possible increasing subsequences of numbers (repetition allowed) from 1 to n, but of length k.
Ex. n=3, k=2
Output:
1 1
1 2
1 3
2 2
2 3
3 3
This is my code:
#include <stdio.h>
int s[100];
int n=6;
int k=4;
void subk(int prev,int index)
{
int i;
if (index==k)
{
for(int i=0; i<k; i++)
printf("%d ",s[i]);
printf("\n");
return;
}
s[index]=prev;
for (i=prev; i<=n; ++i)
{
subk(i,index+1);//,s,n,k);
}
}
int main()
{
int j;
for (j = 1; j<=n ; ++j)
{
subk(j,0);
}
return 0;
}
But this generates some unwanted repetitions. How do I eliminate those?
I have tested your code with n = 3 and k = 2 and got the following result:
1 1
1 1
1 1
1 2
1 2
1 3
2 2
2 2
2 3
3 3
This is obviously incorrect, as there are several identical numbers like 1 1 or 1 2.
But what exactly went wrong?
Let's write down the right results if n = 3 and k = 3. Now compare those to the result we got from the program when n = 3 and k = 2.
correct program (incorrect)
k = 3 k = 2
1 1 1 1 1
1 1 2 1 1
1 1 3 1 1
1 2 2 1 2
1 2 3 1 2
1 3 3 1 3
2 2 2 2 2
2 2 3 2 2
2 3 3 2 3
3 3 3 3 3
Now we can see that the incorrect output of the program is the same as the first two columns of the correct answer when we set k = 3. This means that the program solves the problem for 3 columns if we set k = 2, but only displays the first two columns.
You need to stop the program from writing the same number several times.
Solution 1
One way to do this is to execute the for-loop in the subk-function only once when it writes the last number (index == (k - 1)) into the buffer s.
In order to achieve this, you need to add the following two lines to the end of your for-loop.
if (index == (k - 1))
break;
(Instead of the break you could also use return)
After you added these two lines the function should look like this:
void subk(int prev, int index)
{
int i;
if (index == k)
{
for (int i = 0; i<k; i++)
printf("%d ", s[i]);
printf("\n");
return;
}
s[index] = prev;
for (i = prev; i <= n; ++i)
{
subk(i, index + 1);//,s,n,k);
if (index + 1 == k)
break;
}
}
Solution 2
Another way to solve the problem is to move the line s[index] = prev; to the beginning of the function and change the k in the if-statement to k - 1.
Now the function should look like this:
void subk(int prev, int index)
{
int i;
s[index] = prev;
if (index == k - 1)
{
for (int i = 0; i<k; i++)
printf("%d ", s[i]);
printf("\n");
return;
}
for (i = prev; i <= n; ++i)
{
subk(i, index + 1);//,s,n,k);
}
}
With this solution, the for-loop is never executed when the index shows that the program is at the last 'sub-number'. It just displays the number and exits the function because of the return.
You get the right result with both solutions, but I personally like the second solution better, because there is no additional if-statement that is executed every iteration of the for-loop and the program is (slightly) faster.
I am trying to understand the ShellSort code in K&R book at page 62. But there is one part i am not sure of.
So here is the original code from the book:
void shellsort(int* v, int n) {
int gap, i, j, temp;
for (gap = n / 2; gap > 0; gap /= 2) {
for (i = gap; i < n; i++) {
for (j = i - gap; j >= 0 && v[j] > v[j + gap]; j -= gap) {
temp = v[j];
v[j] = v[j + gap];
v[j + gap] = temp;
}
}
}
}
And i am trying to understand why there is third loop. It could be only if couldnt it?
Here is changed version of code (the one that i think could work as well):
void shellsort(int* v, int n) {
int gap, i, j, temp;
for (gap = n / 2; gap > 0; gap /= 2) {
for (i = gap; i < n; i++) {
j = i - gap;
if (v[j] > v[j + gap]) {
temp = v[j];
v[j] = v[j + gap];
v[j + gap] = temp;
}
}
}
}
And when i run the code, and it outputs the same thing as the first code:
Output:
12345679
But surely there is some reason using for there. And i am not able to find what reason that is. So i thought someone can clear this out?
You might get a better feeling for what's going on if you trace what the algorithm does. Here is a version of your program with some extra print statements:
void shellsort(int* v, int n) {
int gap, i, j, temp;
for (gap = n / 2; gap > 0; gap /= 2) {
printf("enter outer loop with gap = %d\n", gap);
for (i = gap; i < n; i++) {
printf("- enter second loop with i = %d\n", i);
for (j = i - gap; j >= 0 && v[j] > v[j + gap]; j -= gap) {
temp = v[j];
v[j] = v[j + gap];
v[j + gap] = temp;
}
printf("- after innermost loop:");
print_array(v, n);
}
}
}
(I omitted the definition of print_array.)
Calling this with an array { 5, 4, 3, 2, 1 }, as a commenter suggested, gives this output:
5 4 3 2 1
enter outer loop with gap = 2
- enter second loop with i = 2
- after innermost loop: 3 4 5 2 1
- enter second loop with i = 3
- after innermost loop: 3 2 5 4 1
- enter second loop with i = 4
- after innermost loop: 1 2 3 4 5
enter outer loop with gap = 1
- enter second loop with i = 1
- after innermost loop: 1 2 3 4 5
- enter second loop with i = 2
- after innermost loop: 1 2 3 4 5
- enter second loop with i = 3
- after innermost loop: 1 2 3 4 5
- enter second loop with i = 4
- after innermost loop: 1 2 3 4 5
1 2 3 4 5
But here is what happens if I use your code, using just an if instead of the innermost for loop:
5 4 3 2 1
enter outer loop with gap = 2
- enter second loop with i = 2
- after swap: 3 4 5 2 1
- enter second loop with i = 3
- after swap: 3 2 5 4 1
- enter second loop with i = 4
- after swap: 3 2 1 4 5
enter outer loop with gap = 1
- enter second loop with i = 1
- after swap: 2 3 1 4 5
- enter second loop with i = 2
- after swap: 2 1 3 4 5
- enter second loop with i = 3
- after swap: 2 1 3 4 5
- enter second loop with i = 4
- after swap: 2 1 3 4 5
2 1 3 4 5
The result is incorrect because the 1 is not propagated to the beginning of the array. This is due to the missing inner loop. In the original version, at gap = 2 and i = 4, the program compares 5 and 1 and swaps them; then compares 3 and 1 and swaps them as well to ensure that these three elements (1, 3, 5) are in the correct relative order. Without the inner loop, this second swap is not done. There would be a chance to repair this in the iteration with gap = 1, but again 1 is only swapped with one element (3) but not swapped with 2.
Or, for a shorter but more obscure answer: Shell sort performs a loop for various "gap sizes" over a variant of insertion sort. If you know insertion sort, you know that it consists of two nested loops. If you remove the innermost loop, you break the inner insertion sort.
Finally, in your example that just worked, you simply got unlucky: If the input is (mostly) sorted, even broken sorting algorithms can appear to work. These things are hard to test.
I tried to sort arr by excluding those who were already selected as the largest numbers but it didn't work.
The result is this:
As I intended, at first cycle, the store is {9, 0, 0, 0, 0 ... } and when arr[i] becomes 9, the rest of process should be skipped. I have to sort it without additional functions and it's too difficult to me. What is the problem?
int i = 0;
int j = 0;
int num = 0;
int sign = 0;
int arr[10] = { 1,5,3,4,8,7,5,9,8,0 };
int max = arr[0];
int store[10] = { 0 };
int k = 0;
for (j = 0; j < 10; j++) {
printf("store: ");
for (int n = 0; n < 10; on++)
printf("%d ", store[n]);
printf("\n");
for (i = 0; i < 10; i++) {
sign = 0;
k = 0;
while (k < 10) {
if (arr[i] == store[k]) {
sign = 1;
break;
}
k++;
}
if (sign == 1) {
continue;
}
if (arr[i] > max) {
max = arr[i];
}
}
store[j] = max;
}
You have several errors here:
The array store has a size of 10, but in the jth pass through the outer loop, only j values have been filled in; the rest is still zero. So whenever you iterate over store, you should use j as upper limit.
You are looking for the max in each iteration. Therefore, it is not enough to initialise max once outside the outer loop. You do that, and it will stay 9 ever after. You should reset max for every j.
Finally, your idea to go through the array to see whether you have already processed a certain value does not work. Your array has duplicates, two 8's and two 5's. You will only place one eight and one five with your strategy and re-use the last value of max for the last two elements. (Plus, that idea lead to O(n³) code, which is very wasteful.
You can work around that by keeping an extra array where you store whether (1) or not (0) you have already processed a value at a certain index or by setting processed entries in the array to a very low value.
What you want to implement is selection sort: Find the maximum value in the whole list and move it to the front. Then find the maximum in the whole list except the first item and move it to the second slot and so on:
* 1 5 3 4 8 7 5 9 8 0
9 * 5 3 4 8 7 5 1 8 0
9 8 * 3 4 5 7 5 1 8 0
9 8 8 * 4 5 7 5 1 3 0
9 8 8 7 * 5 4 5 1 3 0
9 8 8 7 5 * 4 5 1 3 0
9 8 8 7 5 5 * 4 1 3 0
9 8 8 7 5 5 4 * 1 3 0
9 8 8 7 5 5 4 3 * 1 0
9 8 8 7 5 5 4 3 1 * 0
9 8 8 7 5 5 4 3 1 0 *
Here, all items to the left of the asterisk have been sorted and everything to the right of the asterisk is still unsorted. When the * (at position j) has moved to the right, the whole array is sorted.
This sort is in-place: It destroys the original order of the array. That is useful, because the position of an element tells us whether it has been processed or not. In the third iteration, the algorithm can distinguish between the 8 that has been sorted and the 8 that hasn't been sorted yet. (This sort is often described as sorting a hand of cards: Look fo the lowest, put it to the left and so on. If you must sort into a second array, copy the original array and sort the copy in place.)
Here's the code that sorts your array and prints out the diagram above:
#include <stdlib.h>
#include <stdio.h>
int main()
{
int arr[10] = {1, 5, 3, 4, 8, 7, 5, 9, 8, 0};
int i = 0;
int j = 0;
for (j = 0; j < 10; j++) {
int imax = j;
int swap = arr[j];
// print array
for (i = 0; i < 10; i++) {
if (i == j) printf("* ");
printf("%d ", arr[i]);
}
printf("\n");
// find index of maximum item
for (i = j + 1; i < 10; i++) {
if (arr[i] > arr[imax]) {
imax = i;
}
}
// swap first unsorted item and maximum item
arr[j] = arr[imax];
arr[imax] = swap;
}
// print fully sorted array
for (i = 0; i < 10; i++) {
printf("%d ", arr[i]);
}
printf("*\n");
return 0;
}
Use i and j.
N is 10 and the data consists of shuffled numbers 0 to N-1.
j goes from 0 to N-1. At each step, you want to fill it with
the maximum of the unprocessed input.
So i goes from j+1 to N-1, in the inner loop. If arr[j] < arr[i],
swap arr[i] and arr[j].
It speeds up considerably as you get towards the end.