Strange behaviour in a C code under gcc 4.4.3 - c

I came across this piece of code today while tutoring some students in a C programming language course.
The exercise asked to implement two functions. The first one scans input from a user and the second displays what has been previously scanned.
The code I came across is the following:
#include <stdio.h>
void myInput(int i,int n)
{
int cpt;
int tab[n];
for ( cpt=0; cpt<n; cpt++)
{
printf("Enter a number :");
scanf("%d",&i);
tab[cpt]=i;
}
}
void myDisp (int n)
{
int tab[n];
int cpt;
for ( cpt=0; cpt <n; cpt++)
{
printf("%d ", tab[cpt]);
}
}
int main()
{
int n; int i;
printf(" Entrer the numbers of elements you want: \n");
scanf("%d \n",&n);
int tab[n];
myInput(i,n);
myDisp(n);
}
Although this code is full of inconsistencies, it does actually work under gcc 4.4.3: it displays the numbers that have been input!!!!!!
Does anyone understands how come these code works?
Thanks very much

If that works, it's through sheer dumb luck. What is printed in myDisp is uninitialized stack, which may or may not contain the data that was put into similarly named variables in myInput. Related reading
Here's an easy way to break it with do-nothing code:
void myInput(int i,int n)
{
// Add some variables to mess up the stack positioning.
int breaker;
int cpt;
int stomper;
int tab[n];
int smasher;
for ( cpt=0; cpt<n; cpt++)
{
printf("Enter a number :");
scanf("%d",&i);
tab[cpt]=i;
}
// Trick the compiler into thinking these variables do something.
breaker = 1;
smasher = 3 * breaker;
stomper = smasher + breaker;
breaker = stomper * smasher;
}
Another way to break it would be to put a function call (say, to printf) between the calls to myInput and myDisp.

It doesn't work, at least not consistently. Granted I have gcc 4.4.4 not 4.4.3
$ ./a.out
Entrer the numbers of elements you want:
5
2
Enter a number :Enter a number :4
Enter a number :1
Enter a number :2
Enter a number :3
2 4 1 134514562 3
Moral of the story is when you access uninitialized memory, anything can happen, including the appearance of working.

Since the two arrays are completely separate it really should not work. If it does it's just because they ended up in the same location in memory.

Probably it works because the memory location of the tab local to myInput e myDisp happens to be (almost?) the same.
It doesn't sound so weird to me: myInput and myDisp have almost the same signature (they differ for just one int parameter); even in the worst case scenario the locations on the stack referred by tab in the two functions would be still correctly aligned and shifted at most by two ints (i and cpt in myInput).

It appears the program is accessing the same memory location for every array int tab[n] you declared but, as mentioned, it should not work.
But I think what's happening here is something like: you are allocating tab[] inside main(), let's say, under the address 0x00000001 (take it as an example only). The array have n integers but no values at all.
Then you go into myInput(), declare the array again (same size), in other address, like 0x001F0000, and then set the values, one by one.
So, when the function terminates, it frees the allocated memory of its variables, so your array does not exist anymore.
But wait, this is C, so when you free the memory, you only tells the heap (or the memory allocator, in general) that the addresses can be used again. You do NOT exactly remove the values from memory.
Then you call myDisp() and declare your array again. It appears the memory you just requested has higher priority and then it is somewhat given again to your program. So your array is again instanciated and on the same address.
So, even if you did not fill it with values, the memory is read (as it is always valid in C) and the values are still there.
Oh, and the array declared inside main()? Nothing happens to that. Try to print its values and I bet you'll not have the correct ones.
That is my guess.
EDIT: Just to see things happening: try to declare another array after tab (do not rename tab), say tab2, same length, and use it to put your values instead of tab, then let the program run again :)

Related

Why does c print a different array the second time it's printed?

My cousin has a school project and we can't figure out why is the array different the second time it's printed when there is no values changing in between?
Basically you enter a number which states how many rows/columns will the matrix have, and during first loop he assigns a number to every position and prints out the random number. However, the second time we go through the matrix the numbers are different and it seems that they are copied through the matrix from bottom left corner to top right corner for some reason. It seems strange to us because we never assign a different value to a position in the array after defining it for the first time.
int i,j,n,matrica[i][j],suma=0;
srand(time(NULL));
printf("\nunesi prirodan broj N[3,20] = \n");
scanf("%d",&n);
for(i=0;i<n;i++) {
for(j=0;j<n;j++) {
matrica[i][j]=rand()%100;
printf("%d, %d = %4d ",i, j, matrica[i][j]);
if(j==n-1) {
printf("\n");
}
}
}
printf("\n");
for(i=0;i<n;i++) {
for(j=0;j<n;j++) {
printf("%d, %d = %4d ", i, j, matrica[i][j]);
if(j==n-1) {
printf("\n");
}
}
}
And here is the result of this (the code I pasted here has 2 prints, and in the image there is 3 but every time you go through the matrix after the first time it's going to be the same):
We need to use malloc to allocate the dynamic amount of memory.
After
scanf("%d",&n) // PS You should check the return value - read the manual page
Put
matrica = malloc(sizeof(int) * n * n);
And declare it as
int *matrica;
Then replace
matrica[i][j]
with
matrica[i * n + j]
And after you have finished with matrica - use free i.e.
free(matrica);
int i,j,n,matrica[i][j]
At this point I must ask, what value do you think i and j will have? Right there you're invoking undefined behaviour by referring to variables declared with automatic storage duration which you've not initialised. Anything after this point is... undefined behaviour.
Having said that, I noticed a few other parts that look strange. Which book are you reading? The reason I ask is that the people I know to be reading reputable textbooks don't have these problems, thus your textbook (or resource, whatever) mustn't be working for you...
I can't read the commentary inside of the string literals, which is a shame, since that's usually quite valuable contextual information to have in a question. Nonetheless, moving on, if this were me, I'd probably declare a pointer to an array n of int, after asking for n, like so:
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
int main(void) {
size_t n;
printf("Enter n, please: ");
fflush(stdout);
if (scanf("%zu", &n) != 1 || n == 0 || SIZE_MAX / n < n) {
puts("Invalid input or arithmetic overflow...");
return -1;
}
int (*array)[n] = malloc(n * sizeof *array);
if (!array) {
puts("Allocation error...");
return -1;
}
/* now you can use array[0..(n-1)][0..(n-1)] as you might expect */
free(array);
}
This should work for quite high numbers, much higher than int array[n][n]; would in its place... and it gives you that option to tell the user it was an "Allocation error...", rather than just SIGSEGV, SIGILL, SIGBUS or something...
... but nothing would be more optimal than just saving the seed you use to generate the random numbers, and the user input; that's only two integers, no need for dynamic allocation. There's no point storing what rand generates, amd you realise this, right? rand can generate that output purely using register storage, the fastest memory commonly available in our processors. You won't beat it with arrays, not meaningfully, and not... just not.

Code to change an array element changes a different variable

I'm quite puzzled by why my variable NumberOfArrays changes the second time through the for loop in my code. Can anyone help me out?
#include <stdio.h>
#include <cs50.h>
int main(int argc, string argv[])
{
//variable declarations
int NumberOfArrays = 0;
int arrayRack[0];
//Get number of arrays
printf("Key in the number of arrays you'd like to have\n");
NumberOfArrays = GetInt();
//Get number for each element in arrayRack[]
for(int i = 0; i < NumberOfArrays; i++)
{
printf("give me an int for the %i th array\n", i + 1);
arrayRack[i] = GetInt();
// *** on the second pass, my "NumberOfArrays" gets adjusted to my GetInt number here. Why?
}
//print out numbers stored in respective arrays
for(int j = 0; j < NumberOfArrays; j++)
{
printf("{%i}<-- number in %ith array\n", arrayRack[j], j + 1);
}
return 0;
}
Because you declared arrayRack as an empty array ([0]). Try int arrayRack[100]; or some other number, and make sure that NumberOfArrays is less than that number before you use it.
Explanation: (edit note that this may vary by compiler) your variables are most likely stored on the stack in nearby memory addresses. So arrayRack points somewhere close to NumberOfArrays in memory. C doesn't generally check if you've run off the end of an array, so accessing arrayRack[1] doesn't cause a compiler error in this situation. However, arrayRack[1] isn't part of your array, so accessing it actually accesses something else — in this situation, NumberOfArrays.
Edit gcc permits length-0 arrays but does not allocate space for them per this. However, length-0 arrays are prohibited by the C standard (e.g., see this, the answers to this, and this). Given the behaviour you've seen, it looks to me like the compiler is allocating one int's worth of space on the stack, pointing arrayRack to that space, and packing that space right next to NumberOfArrays. As a result, &(arrayRack[1]) == &NumberOfArrays. In any event, using variable-length arrays as suggested by #dasblinkenlight is a cleaner way to handle this situation.
In general, given int arrayRack[N];, you can only safely access arrayRack[0] through arrayRack[N-1].
You declared the array too early. Move the declaration to after the call of GetInt(), like this:
printf("Key in the number of arrays you'd like to have\n");
int NumberOfArrays = GetInt();
int arrayRack[NumberOfArrays];
Note: NumberOfArrays is not an ideal name for the variable, because it denotes the number of array elements, not the number of arrays; your code has only one array.

Array with No Upper Boundaries in C

I have been attempting to wrap my head around an idea that I am certain is possible, I just am not sure if I am going about it in the right way. My intention is to create an array and then fill it with as many values as the user wants. However my goal is to not use any defined value per se. I would like to be able to continue increasing it the amount of values it can contain indefinitely.
This is the test code I have been using to try and figure this out:
#include <stdio.h>
#include <stdlib.h>
int main(void)
{
int i;
int Up;
int Ary[0];
printf("Please enter the number of integers you want to input: ");
scanf("%d", &Up);
for(i = 0; i < Up; i++)
{
printf("Please enter a number: ");
Ary[i] = (int) malloc(sizeof(int));
scanf("%d", &Ary[i]);
}
for(i = 0; i < Up; i++)
{
printf("%d ", Ary[i]);
if(i % 10 == 0)
{
printf("\n");
}
}
return 0;
}
This may be a poor way of attempting to figure this out and I may also be doing this is a completely wrong way; However I get a segmentation fault sometimes. If I use small values such as only entering 4 or 5 values it works fine, however if I enter 10 values it gives me a segmentation fault. If I enter 50 values, it lets me enter all 50 but gives me a segmentation fault after printing out the 41st value.
The code itself is simply a means to an end. Ultimately what I would like to know is how I can set up an array of anything that can have values added to it indefinitely while retaining previous values using dynamic memory allocation?
PS. I hope this defines my question well enough, however if it does not I would like to refine my question so it is more clear. Please make a comment if this is unclear and why.
This isn't going to work:
int Ary[0];
You've made an array with no elements; the only valid use of such an array is to take its address, but you can't index into it as you have done.
Instead, you should make a pointer to what will later be allocated as an array:
int *Ary;
Then when you know how many integers you want:
Ary = malloc(Up * sizeof(int));
Now you can do Ary[index] for any index from 0 to (Up-1). If you later want to enlarge the array, you can use realloc() (many tutorials online for that).
You need to use dynamic allocation, what you are doing right now is static allocation, you need to learn how to use malloc and free.
So keep in mind that what you want to do is not "efficient" but can definitely be done as a learning exercise to learn how to make such a container.
What you need to do is allocate the amount of memory needed to contain the amount of values currently in your array +1 more value every time you want to "add" a new value to your array, for example: malloc(sizeof(int)*(<current_number_of_values>+1)).
I say "add" in quotes because what you will have to do is actually allocate memory for a brand new array every time and copy over your old values plus the new value the user enters and then free your old array to avoid memory leaks.
There are STL containers that do this internally but much more efficiently but I assume you are doing this to learn and not use your own containers for anything serious.

Is it possible to include loop counter in name of array when declaring it? (in C)

I have this loop which creates a certain number of array depending on a value input by the user. I want to include the counter of the array at the end of the array name such that it is: array1[], array2[], array3[] and so on, one for each iteration. Would this be possible? We have just started learning C now at university so I don't know much about it yet. I tried the following:
#include <stdio.h>
int main(void)
{
//Variables
int i, columns, column_size;
//Read input
printf("Input number of columns:\n");
scanf("%d", &columns)
//Loop to create arrays
for (i=1; i<=columns; i=i+step)
{
//Read column size
scanf("%d", &column_size);
//Create an array of given size for this column
int column+"i"+[column_size];
}
return 0;
}
I want to include the counter of the array at the end of the array name such that it is: array1[], array2[], array3[] and so on, one for each iteration
That is not possible. C is a compiled language, meaning that a program (the compiler) creates the program at one point in time and the program eats user-input at a different point in time.
Even the names of the "variables" might vanish after compilation, they are not needed to execute the program.
int a;
All this does is to tell the compiler that you, the programmer need 32bits of space to store something. If you want to store something there later on, you use the name "a":
a = 42;
The compiler calculates the offset to your current location in RAM and stores the "42" at that address. At runtime the used "names" are completely irrelevant, there is no lookup for the right place involved.
This is the difference to an "interpreted language" like Python.

Why does the program crash when the function is called in c?

I recently had to create a program where the user enters a certain integer N. After that, my int main() had to call a seperate function, int getNextFibonacciNumber(void), which calculates the Nth term in the fibonacci sequence and then prints it. When I compile the code, Vode::Blocks says that there aren't any errors or warnings. This said, when I try to run the program, it automatically crashes. I have read it and re-read it but I am not able to see where it all went wrong. Would anyone be able to shed some light on this mysery? Thank you very much! When the program crashes, it says: filename.exe has stopped working. A problem caused the program to stop working correctly. Windows will close the program and notify you if a solutions is available. However, when the code is compiled in Code::Blocks, everything is fine.
#include <stdio.h>
#include <stdlib.h>
int getNextFibonacciNumber(void);
int main()
{
int N, fibonacci[N];
printf("Enter a positive integer:");
scanf("%d", &N);
printf("The %d th term in the Fibonacci sequence is: %d", N, getNextFibonacciNumber());
}
int getNextFibonacciNumber()
{
int N, i, fibonacci[N];
fibonacci[0] = 0;
fibonacci[1] = 1;
for(i = 2; i < N+1; i++)
{
fibonacci[i] = fibonacci[i-1] + fibonacci[i-2];
}
return(fibonacci[N-1]);
}
The problem is, that this
int main()
{
int N, fibonacci[N];
invokes undefined behavior. N is not initialized, but used as a C99 variable length array size specifier. Reading a value from a uninitialized variable invokes UB.
To fix this issue you have to write
int main()
{
int N;
printf("Enter a positive integer:");
scanf("%d", &N);
int fibonacci[N];
However there's another problem, namely that you have the same UB causing construct in getNextFibonacciNumber. You have to fix that to. Also the number entered into N is not "communicated" to getNextFibonacciNumber, so I highly doubt that this program worked at all, even if it didn't crash.
Code::Blocks (or rather the compiler Code::Blocks calls) only checks if you have written "legal" c code. It does not (and can not) check if your program does what you want, if your program will exit at any point (or simply run forever), if your program causes errors and crashs and stuff like this.
When you say
int N, fibonacci[N];
I guess you want to create an integer N and an array of the same size. However right now you create an integer N (that has some "random" value, presumably 0) and an array of the FIXED size N.
If you change N late on in your program this does not affect the size of your array "fibonacci" in any way. So if your N was by chance 0 at the beginning of your program than you have created an array of size 0. Even if you read a value (say 5) from the console input. Trying to read and write to this array causes problems.
Moving the part
int fibonacci[N];
below your "scanf" line will fix this problem. At this point N is initialized (and not some random number).
Also be aware that the variable N in the main function
int main()
has no connection at all to the N variable in your function
int getNextFibonacciNumber()
The second N is a newly created variable (again set to some "random" value). If you want to pass data from one function to another you should do it by passing it as an argument in brackets:
int getNextFibonacciNumber( int N)

Resources