code order with variable length array - c

In C99, is there a big different between these two?:
int main() {
int n , m;
scanf("%d %d", &n, &m);
int X[n][m];
X[n-1][m-1] = 5;
printf("%d", X[n-1][m-1]);
}
and:
int main(int argc, char *argv[]) {
int n , m;
int X[n][m];
scanf("%d %d", &n, &m);
X[n-1][m-1] = 5;
printf("%d", X[n-1][m-1]);
}
The first one seems to always work, whereas the second one appears to work for most inputs, but gives a segfault for the inputs 5 5 and 6 6 and returns a different value than 5 for the input 9 9. So do you need to make sure to get the values before declaring them with variable length arrays or is there something else going on here?

When the second one works, it's pure chance. The fact that it ever works proves that, thankfully, compilers can't yet make demons fly out of your nose.
Declaring a variable doesn't necessarily initialize it. int n, m; leaves both n and m with undefined values in this case, and attempting to access those values is undefined behavior. If the raw binary data in the memory those point to happen to be interpreted into a value larger than the values entered for n and m -- which is very, very far from guaranteed -- then your code will work; if not, it won't. Your compiler could also have made this segfault, or made it melt your CPU; it's undefined behavior, so anything can happen.
For example, let's say that the area of memory that the compiler dedicates to n happened to contain the number 10589231, and m got 14. If you then entered an n of 12 and an m of 6, you're golden -- the array happens to be big enough. On the other hand, if n got 4 and m got 2, then your code will look past the end of the array, and you'll get undefined behavior -- which might not even break, since it's entirely possible that the bits stored in four-byte segments after the end of the array are both accessible to your program and valid integers according to your compiler/the C standard. In addition, it's possible for n and m to end up with negative values, which leads to... weird stuff. Probably.
Of course, this is all fluff and speculation depending on the compiler, OS, time of day, and phase of the moon,1 and you can't rely on any numbers happening to be initialized to the right ones.
With the first one, on the other hand, you're assigning the values through scanf, so (assuming it doesn't error) (and the entered numbers aren't negative) (or zero) you're going to have valid indices, because the array is guaranteed to be big enough because the variables are initialized properly.
Just to be clear, even though variables are required to be zero-initialized under some circumstances doesn't mean you should rely on that behavior. You should always explicitly give variables a default value, or initialize them as soon as possible after their declaration (in the case of using something like scanf). This makes your code clearer, and prevents people from wondering if you're relying on this type of UB.
1: Source: Ryan Bemrose, in chat

int X[n][m]; means to declare an array whose dimensions are the values that n and m currently have. C code doesn't look into the future; statements and declarations are executed in the order they are encountered.
In your second code you did not give n or m values, so this is undefined behaviour which means that anything may happen.
Here is another example of sequential execution:
int x = 5;
printf("%d\n", x);
x = 7;
This will print 5, not 7.

The second one should produce bugs because n and m are initialized with pretty much random values if they're local variables. If they're global, they'll be with value 0.

Related

number of elements exceed the size declared in array in c

int main(void)
{
int b[5] = {1,2,3,4,5,6,7,8,9,10};
int i;
for(i=0;i<9;i++)
{
printf(" %d ",b[i]);
}
printf("\n address : %u",b);
return 0;
}
This is C program in which number of elements exceeds declared size. when i iterate through array it prints following output-
1 2 3 4 5 5 6422284 3854336 6422352
address : 6422288
compiler - gcc
i don't understand
why 5 is printed twice
why only 9 values are printed instead of 10
Because the behavior of the program is not defined, and thus it will do whatever. Your expectation that “5 should not be printed twice” is just as speculative as any other expectation. Why do you think 5 should not be printed twice?!
Because the behavior of the program is not defined. Thus your expectation as to the behavior of the loop is just idle speculation.
You’ll see even more interesting things happen if you do a release (optimized) build. It may do nothing whatsoever, or crash, or do the same thing, or do something else out of the blue if the CPU’s IP gets corrupted or sent into the “blue”.
And by the way, your original program could too :)
The C language specification contains the following constraint (C17 6.7.9/2):
No initializer shall attempt to provide a value for an object not
contained within the entity being initialized.
Your initialization of b ...
int b[5] = {1,2,3,4,5,6,7,8,9,10};
... violates that constraint by including ten values in b's initializer list when b has only five elements, all scalars. A conforming compiler is obligated to emit a diagnostic about that, and if gcc does not do so by default then it probably can be made to do so by including the -pedantic flag. Generally speaking, with gcc you should use both -Wall and -pedantic at least until you know enough to make an informed decision of your own.
Technically, the behavior of your program is undefined as a result, but that's probably not the main issue in practice. I expect that gcc is just ignoring the excess initializer values. The main issue is that no matter how many initializer elements you provide, you have specified that b has exactly 5 elements, but you attempt to access elements at indices above 4. Those are out of bounds array accesses, and their behavior is undefined. You have no valid reason to expect any particular results of those, or that anything be printed at all.
In fact, the whole program has undefined behavior as a result, so it is not safe to assume that a program that performed all the same things except the out-of-bounds accesses would produce a subset of the output of the erroneous program.
With respect to your particular questions:
why 5 is printed twice
The language specification does not say. The result of attempting to print b[5] is undefined.
why only 9 values are printed instead of 10
Probably because of the iteration bounds, i=0;i<9;i++. With those, and if the program otherwise conformed to the language specification, one would expect the loop body to be executed nine times (in particular, not when i has the value 9).
Note also that this ...
printf("\n address : %u",b);
... is wrong. The printf directive for printing pointers is %p, and, technically, it requires the argument to be a pointer to void (not, for example, a pointer to int). This would be fully correct:
printf("\n address : %p", (void *) b);
Addendum
If you want an array with exactly ten elements, then declare it so:
int b[10] /* initializer optional */;
If you want one whose size is chosen based on the number of elements in its initializer, then omit the explicit size:
int b[] = {1,2,3,4,5,6,7,8,9,10}; /* declares a 10-element array */

Searching for all integers that occure twice in a vector

I got the task in university to realize an input of a maximum of 10 integers, which shall be stored in a one dimensional vector. Afterwards, every integer of the vector needs to be displayed on the display (via printf).
However, I don't know how to check the vector for each number. I thought something along the lines of letting the pointer of the vector run from 0 to 9 and comparing the value of each element with all elements again, but I am sure there is a much smarter way. I don't in any case know how to code this idea since I am new to C.
Here is what I have tried:
#include <stdio.h>
int main(void)
{
int vector[10];
int a;
int b;
int c;
a = 0;
b = 0;
c = 0;
printf("Please input 10 integers.\n\n");
while (a <= 10);
{
for (scanf_s("%lf", &vektor[a]) == 0)
{
printf("This is not an integer. Please try again.\n");
fflush(stdin);
}
a++;
}
for (b <= 10);
{
if (vector[b] != vector[c]);
{
printf("&d", vector[b]);
c++;
}
b++;
}
return 0;
}
Your code has several problems, some syntactic and some semantic. Your compiler will help with many of the former kind, such as
misspelling of variable name vector in one place (though perhaps this was a missed after-the-fact edit), and
incorrect syntax for a for loop
Some compilers will notice that your scanf format is mismatched with the corresponding argument. Also, you might even get a warning that clues you in to the semicolons that are erroneously placed between your loop headers and their intended bodies. I don't know any compiler that would warn you that bad input will cause your input loop to spin indefinitely, however.
But I guess the most significant issue is that the details of your approach to printing only non-duplicate elements simply will not serve. For this purpose, I recommend figuring out how to describe in words how the computer (or a person) should solve the problem before trying to write C code to implement it. These are really two different exercises, especially for someone whose familiarity with C is limited. You can reason about the prose description without being bogged down and distracted by C syntax.
For example, here are some words that might suit:
Consider each element, E, of the array in turn, from first to last.
Check all the elements preceding E in the array for one that contains the same value.
If none of the elements before E contains the same value as E then E contains the first appearance of its value, so print it. Otherwise, E's value was already printed when some previous element was processed, so do not print it again.
Consider the next E, if any (go back to step 1).

What exactly happens if I declare a 10 elements array and try to access a bigger position within it?

It just happened to me. A bug. I set a 5 element array and a position variable to scroll through all its index:
int matematica[5];
int pos = 0;
and then I had my loop working just ok. Like this:
while (pos < 5) {
printf("Entre com o número da matrícula do %dº aluno: \n", pos+1);
scanf("%d", &num);
if (num != 35)
matematica[pos] = num;
pos++;
}
Everything working like a charm. After that, I had do the same to 150 positions, so I changed the while loop from while (pos < 5) to while (pos < 150) but forgot to do the same with the array. What happened then is the object of my question itself. The program didn't crash or something, it just happened that the printf and scanf statements run a bit more than 5 times then stops (sometimes 8 times, sometimes 7...)
Why does that happens. I of course fixed it later, but I still can't grasp the logic behind that bug.
The C standard says this triggers Undefined behavior,
anything could happen.
It could appear to work "correctly"
it could terminate with an error code.
it could do something unexpected.
This type of bug is called a buffer overrun, and these can often lead to arbitrary code execution (which is a special subclass of "something unexpected")
In your example pos probably occupies the same memory as matematica[5], (because most (all?) compilers pack global variables together much like fields in a struct) so depending on what number you enter in the sixth place the loop may stop or continue, negative numbers could cause
interesting results.
When you declare your array to be the array of 5 integers, you reserve a chunk of memory which holds it and then, you receive a pointer to it (which you can use however you want). When you call for an array like matematica[0], then you point to the beginning of an array and use value, which is out there. Then, when you call matematica[6] (which is outside the boundaries), you still reach the very same memory, but outside your array. It is totally legal, but it is unknown what is stored there. When you upload any other value there, you might overwrite your own data and cause weird bugs, and when you try to read it, it will be probably a random number. It will not crash, but you are warned :)

Array Allocation causing terminal to hang

I came across this code accidentally:
#include<stdio.h>
int main()
{
int i;
int array[3];
for(i=0;i<=3;i++)
array[i]=0;
return 0;
}
On running this code my terminal gets hanged - the code is not terminating.
When I replace 3 by 2 code runs successfully and terminates without a problem.
In C there is no bound checking on arrays, so what's the problem with the above code that is causing it to not terminate?
Platform - Ubuntu 10.04
Compiler - gcc
Just because there's no bound checking doesn't mean that there are no consequences to writing out of bounds. Doing so invokes Undefined Behavior, so there's no telling what may happen.
This time, on this compiler, on this architecture, it happens that when you write to array[3], you actually set i to zero, because i was positioned right after array on the stack.
Your code is reading beyond the bound of array and causing an Undefined Behavior.
When you declare an array of size 3. The valid index range is from 0 to 2.
While your loop runs from 0 to 3.
If you access anything beyond the valid range of an array then it is Undefined Behavior and your program may hang or crash or show any behavior. The c standard does not mandate any specific behavior in such cases.
When you say C does not do bounds checking it actually means that it is programmers responsibility to ensure that their programs do not access beyond the beyonds of the allocated array and failing to do so results in all safe bets being off and any behavior.
int array[3];
This declares an array of 3 ints, having indices 0, 1, and 2.
for(i=0;i<=3;i++)
array[i]=0;
This writes four ints into the array, at indices 0, 1, 2, and 3. That's a problem.
Nobody here can tell exactly what you're seeing -- you haven't even specified what platform you're working on. All we can say is that the code is broken, and that leads to whatever result you're seeing. One possibility is that i is stored right after array, so you end up setting i back to 0 when you do array[3]=0;. But that's just a guess.
The highest valid index for array is 2. Writing past that index invokes undefined behaviour.
What you're seeing is a manifestation of the undefined behaviour.
Contrast this with the following two snippets, both of which are correct:
/* 1 */
int array[3];
for(i=0;i<3;i++) { array[i] = 0; }
/* 2 */
int array[4];
for(i=0;i<4;i++) { array[i] = 0; }
You declared array of size 3 which means (0,1,2 are the valid indexes)
if you try to set 0 to some memory location which is not for us unexpected (generally called UB undefined behavior) things can happen
The elements in an array are numbered 0 to (n-1). Your array has 3 spots, but is initializing 4 location (0, 1, 2, 3). Typically, you'd have you for loop say i < 3 so that your numbers match, but you don't go over the upper bound of the array.

How is this loop ending and are the results deterministic?

I found some code and I am baffled as to how the loop exits, and how it works. Does the program produce a deterministic output?
The reason I am baffled is:
1. `someArray` is of size 2, but clearly, the loop goes till size 3,
2. The value is deterministic and it always exits `someNumber` reaches 4
Can someone please explain how this is happening?
The code was not printing correctly when I put angle brackets <> around include's library names.
#include <stdlib.h>
#include <time.h>
#include <stdio.h>
int main() {
int someNumber = 97;
int someArray[2] = {0,1};
int findTheValue;
for (findTheValue=0; (someNumber -= someArray[findTheValue]) >0; findTheValue++) {
}
printf("The crazy value is %d", findTheValue);
return EXIT_SUCCESS;
}
Accessing an array element beyond its bounds is undefined behavior. That is, the program is allowed to do anything it pleases, reply 42, eat your hard disk or spend all your money. Said in other words what is happening in such cases is entirely platform dependent. It may look "deterministic" but this is just because you are lucky, and also probably because you are only reading from that place and not writing to it.
This kind of code is just bad. Don't do that.
Depending on your compiler, someArray[2] is a pointer to findTheValue!
Because these variables are declared one-after-another, it's entirely possible that they would be positioned consecutively in memory (I believe on the stack). C doesn't really do any memory management or errorchecking, so someArray[2] just means the memory at someArray[0] + 2 * sizeof(int).
So when findTheValue is 0, we subtract, then when findTheValue is 1, we subtract 1. When findTheValue is 2, we subtract someNumber (which is now 94) and exit.
This behavior is by no means guaranteed. Don't rely on it!
EDIT: It is probably more likely that someArray[2] just points to garbage (unspecified) values in your RAM. These values are likely more than 93 and will cause the loop to exit.
EDIT2: Or maybe someArray[2] and someArray[3] are large negative numbers, and subtracting both causes someNumber to roll over to negative.
The loop exits because (someNumber -= someArray[findTheValue]) doesnt set.
Adding a debug line, you can see
value 0 number 97 array 0
value 1 number 96 array 1
value 2 number 1208148276 array -1208148180
that is printing out findTheValue, someNumber, someArray[findTheValue]
Its not the answer I would have expected at first glance.
Checking addresses:
printf("&someNumber = %p\n", &someNumber);
printf("&someArray[0] = %p\n", &someArray[0]);
printf("&someArray[1] = %p\n", &someArray[1]);
printf("&findTheValue = %p\n", &findTheValue);
gave this output:
&someNumber = 0xbfc78e5c
&someArray[0] = 0xbfc78e50
&someArray[1] = 0xbfc78e54
&findTheValue = 0xbfc78e58
It seems that for some reason the compiler puts the array in the beginning of the stack area, then the variables that are declared below and then those that are above in the order they are declared. So someArray[3] effectively points at someNumber.
I really do not know the reason, but I tried gcc on Ubuntu 32 bit and Visual Studio with and without optimisation and the results were always similar.

Resources