code link
#include <stdio.h>
int main(void) {
// your code goes here
int a = 2;
int b = 3;
int c;
c = a + b;
int arr[c];
arr[5] = 0;
printf("%d",arr[5]);
return 0;
}
Output is 0
How is it that at runtime it is taking the array number ? Is it a new feature ?
This is a variable length array. They were introduced in the 1999 revision of the C standard.
Sadly support for them came in slowly, so much that the 2011 revision made them an optional feature (but they are still standardized) 1.
Despite looking cool, they have a major caveat. They can cause you to overflow the call stack if the size is "too big". As such, care needs to be taken when using them.
1 Some compiler vendors were resistant, so it was made optional to appease them. Microsoft is an entire case study of this.
This feature (Variable length array) has been introduced in C99. But currently this still is a compiler-dependent behavior. Some compiler(like gcc) supports it. Some(like msvc) doesn't.
BTW, arr[5] in your code, is out of range. Last element should be arr[4].
don't be confused in (static/fixed memory allocation) & (dynamic memory allocation) concepts :)
Let me clear your concept bro.
Relevant to following question,
C supports two type of array.
1.Static Array - are allocated memory at "COMPILE TIME".
2.Dynamic Array - are allocated memory at "RUN TIME".
Ques. how to determine if an Array is static or dynamic?
Ans.
Array declaration syntax:-
int array_Name[size]; //size defines the size of block of memory for an array;
So, coming to the point-->
Point 1. if size is given at compile time to array, it's a "Static Memory Allocation". It is also called "fixed size memory allocation" because size is never changed. It's the LIMITATION of ARRAY in C.
ex.
int arr[10]; //10 is size of arr which is staticly defined
int brr[] = {1000, 2, 37, 755, 3}; //size is equal to the no. of values initilizes with.
point 2. If size is given at compile time to array, it's a Dynamic Memory Allocation.
It is achieved by malloc() function defined in stdlib.h .
Now, its's the clarification of your code :-
#include <stdio.h>
int main(void) {
// your code goes here
int a = 2;
int b = 3;
int c;
c = a + b; //c is calculated at run time
int arr[c]; //Compilor awaiting for the value of c which is given at run time but,
arr[5] = 0; //here arr is allocated the size of 5 at static(compile) time which is never be change further whether it is compile time in next statements or run time.
printf("%d",arr[5]);
return 0;
}
So, array(of size 5) holds value 0 at arr[5].
and ,other array indexes still show Garbage Values.
Hoping, you'll be satisfy with this solution to your problem :)
Related
I am creating an int array and then tricking c into believing that it's an array of short values. I know it's not good practice but I am just trying to understand why this isn't working. Shouldn't this change the value of arr[3] ?
#include <stdio.h>
int main() {
printf("Hello, World!\n");
int arr[5];
arr[0] = 0; arr[1] = 0; arr[2] = 0; arr[4] = 0;
arr[3] = 128;
((short*)arr)[6] = 128; // Shouldn't this change arr[3] ? as 6,7 indices in the arr of short would compromise of arr[3] in arr of ints?
int i = 0;
for (i = 0; i < 5; i++){
printf("%d\n", arr[i]);
}
return 0;
}
PS: Here's a deeper clarification:
When I cast int array to a short array, it seemingly becomes an array of 10 short elements (not 5). So when I change arr[6], I am changing only the first 16 bits of the int arr[3]. So arr[3] should still change and it is NOT that I am changing it to 128 again and not seeing the change.
FOR CLARIFICATION: THIS CODE IS ONLY FOR EXPERIMENTAL REASONS! I AM JUST LEARNING HOW POINTERS WORK AND I GET THAT ITS NOT GOOD PRACTICE.
Your code has undefined behavior, because you are writing a datum with a declared type through a pointer to a different type, and the different type is not char.
int arr[5];
/* ... */
((short*)arr)[6] = /* ANYTHING */;
The compiler is entitled to generate machine code that doesn't include the write to ((short*)arr)[6] at all, and this is quite likely with modern compilers. It's also entitled to delete the entire body of main on the theory that all possible executions of the program provoke undefined behavior, therefore the program will never actually be run.
(Some people say that when you write a program with undefined behavior, the C compiler is entitled to make demons fly out of your nose, but as a retired compiler developer I can assure you that most C compilers can't actually do that.)
Have you considered endianness?
EDIT: Now to add more clarity ...
As others have mentioned in the comments, this is most definitely undefined behavior! This is not just "not good practice", it's just don't do it!
Pointers on C is an excellent book that goes over everything you wanted to know about pointers and more. It's dated but still very relevant. You can probably find most of the information online, but I haven't seen many books that deal with pointers as completely as this one.
Though it sounds like you are experimenting, possibly as part of a class. So, here are a number of things wrong with this code:
endianness
memory access model
assumption of type size
assumption of hardware architecture
cross type casting
Remember, even though C is considered a pretty low level language today, it is still a high level programming language that affords many key abstractions.
Now, look at your declaration again.
int arr[5];
You've allocated 5 ints grouped together and accessed via a common variable named arr. By the standard, the array is 5 elements of at least 2 bytes per element with base address of &arr[0]. So, you aren't guaranteed that an int is 2 bytes, or 4 bytes or whatever. Likewise, as short is defined by the standard as at least 2 bytes. However, a short is not an int even if they have the same byte width! Remember, C is strongly typed.
Now, it looks like you are running on a machine where shorts are 2 bytes and ints are 4 bytes. That is where the endianness issue come into play: where is your most significant bit? And where is your most significant byte?
By casting the address of arr to a short pointer first of all breaks both the type and the memory access model. Then, you want to access the 6th element from the offset of arr. However, you aren't accessing relative to the int you declared arr to be, you are accessing through a short pointer that is pointing at the same address as arr!
These following operations ARE NOT the same! And it also falls into the category of undefined - don't do this ever!
int foo;
int pfooInt;
short bar;
short * pfooShort;
bar = (short) foo;
pfooShort = (short*)&foo;
pfooInt = &foo;
bar = *pfooShort;
pfooShort = (short*)pfooInt[0];
Another thing to clarify for you:
int arr[5];
((short *)arr)[6] ...
This does not transform your int array of 5 elements into a short array with 10 elements. arr is still an int array of 5 elements. You just broke the access method and are trying to modify memory in an undefined manner. What you did is tell the compiler "ignore what I told you about arr previously, treat arr as a short pointer for the life of this statement and access/modify 6th short relative to this pointer."
It is changing arr[3], however you are setting it back to 128 so you arent noticing a change. Change the line to:
((short*)arr)[6] = 72;
and you should see the following output:
Also a couple of things to clean up if you are new to C. You can initialize an array to zero by doing the following.
...
int arr[5] = { 0 };
arr[3] = 128;
...
Hope this helps!
Closed. This question needs details or clarity. It is not currently accepting answers.
Want to improve this question? Add details and clarify the problem by editing this post.
Closed 7 years ago.
Improve this question
In introductory books on C it is often claimed that pointers more or less are arrays. Isn't this a vast simplification, at best?
There is an array type in C and it can behave completely different from pointers, for example:
#include <stdio.h>
int main(int argc, char *argv[]){
int a[10] = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9};
int *b = a;
printf("sizeof(a) = %lu\n", sizeof(a));
printf("sizeof(b) = %lu\n", sizeof(b));
return 0;
}
gives the output
sizeof(a) = 40
sizeof(b) = 8
or as another example a = b would give a compilation error (GCC: "assignment to expression with array type").
Of course there is a close relationship between pointers and arrays, in the sense that yes, the content of an array variable itself is the memory address of the first array element, e.g. int a[10] = {777, 1, 2, 3, 4, 5, 6, 7, 8, 9}; printf("a = %ul\n", a); prints the address containing the 777.
Now, on the one hand, if you 'hide' arrays in structs, you can easily copy large amounts of data (arrays if you ignore the wrapping struct) just by using the = operator (and that's even fast, too):
#include <sys/time.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define ARRAY_LENGTH 100000000
typedef struct {int arr[ARRAY_LENGTH];} struct_huge_array;
int main(int argc, char *argv[]){
struct_huge_array *a = malloc(sizeof(struct_huge_array));
struct_huge_array *b = malloc(sizeof(struct_huge_array));
int *x = malloc(sizeof(int)*ARRAY_LENGTH);
int *y = malloc(sizeof(int)*ARRAY_LENGTH);
struct timeval start, end, diff;
gettimeofday(&start, NULL);
*a = *b;
gettimeofday(&end, NULL);
timersub(&end, &start, &diff);
printf("Copying struct_huge_arrays took %d sec, %d µs\n", diff.tv_sec, diff.tv_usec);
gettimeofday(&start, NULL);
memcpy(x, y, ARRAY_LENGTH*sizeof(int));
gettimeofday(&end, NULL);
timersub(&end, &start, &diff);
printf("memcpy took %d sec, %d µs\n", diff.tv_sec, diff.tv_usec);
return 0;
}
Output:
Copying struct_huge_arrays took 0 sec, 345581 µs
memcpy took 0 sec, 345912 µs
But you cannot do this with arrays itself. For arrays x, y (of the same size and of the same type) the expression x = y is illegal.
Then, functions can't return arrays. Or if arrays are used as arguments, C collapses them into pointers -- it does not care if the size is explicitly given, so the following program gives the output sizeof(a) = 8:
#include <stdio.h>
void f(int p[10]){
printf("sizeof(a) = %d\n", sizeof(p));
}
int main(int argc, char *argv[]){
int a[10] = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9};
f(a);
return 0;
}
Is there any logic behind this aversion to arrays? Why isn't there a true robust array type in C? What bad would happen if there was one? After all, if an array is hidden in a struct the array does behave as in Go, Rust, ..., i.e. the array is the whole chunk in memory and passing it around will copy its content, not just the memory address of the first element. For example like in Go the following program
package main
import "fmt"
func main() {
a := [2]int{-777, 777}
var b [2]int
b = a
b[0] = 666
fmt.Println(a)
fmt.Println(b)
}
gives the output:
[-777 777]
[666 777]
The C language was initially designed in the early 1970's on a PDP mini-computer which reportedly just filled up half a room, despite its huge 24 kB memory. (That's kB, not MB, or GB).
Fitting a compiler at all into that memory was the real challenge. So the C language was designed to allow you to write compact programs, and quite a few special operators (like +=, --, and ?:) was added for manual optimizations.
Adding features for copying large arrays as parameters didn't occur to the designers. It wouldn't have been useful anyway.
In C's predecessor, the B language, an array was represented as a pointer to storage allocated separately (see the link in Lars' answer). Ritchie wanted to avoid this extra pointer in C and so got the idea that the array name could be turned into a pointer when used in places not expecting an array:
It eliminated the materialization of the pointer in storage, and instead caused the creation of the pointer when the array name is mentioned in an expression. The rule, which survives in today's C, is that values of array type are converted, when they appear in expressions, into pointers to the first of the objects making up the array.
This invention enabled most existing B code to continue to work, despite the underlying shift in the language's semantics.
And structs didn't get added to the language until later. That you can pass an array inside a struct as a parameter was then a feature that offered another option.
Changing the syntax for arrays was already too late. It would break too many programs. There were already 100s of users...
This part of the question...
Is there any logic behind this aversion to arrays? Why isn't there a true robust array type in C? What bad would happen if there was one?
... is not really a code question and open to speculation, but I think a short answer might be beneficial: when C was created, it was targeted at machines with very little RAM and slow CPUs (measured in Kilo-Bytes and Megahertz, resp.). It was meant to replace Assembler as systems programming language, but without introducing the overhead that the other existing high-level languages required. For the same reasons, C is still a popular language for micro controllers, due to the control it gives you over the generated program.
Introducing a 'robust' array type would have had under-the-hood performance and complexity penalties for both the compiler and the runtime, which not all systems couldn't afford. At the same time, C offers the capabilities for the programmer to create their own 'robust' array type and use them only in those situations where its use was justified.
I found this article interesting in this context: Dennis Ritchie: Development of the C Language (1993)
Arrays are arrays and pointers are pointers, they are not the same.
But to make anything usable of arrays the compiler must use qualified pointers.
By definition an array is a contiguous and homogeneous sequence of elements in memory. So far so good, but how interact with it?
To explain the concept I already used, on other forums, an assembly example:
;int myarray[10] would be defined as
_myarray: .resd 10
;now the pointer p (suppose 64 bit machine)
_p: .resq 1
This is the code emitted by compiler to reserve an array of 10 int and a pointer to int in global memory.
Now when referring to the array what you think you can get? Just the address of course (or better the address of the first element). And the address what is? The standard says that it have to be called qualified pointer, but you can really understand now why it is so.
Now look the pointer, when we refer to it the compiler emits code to fetch the contents of the location at address p, but we can even get p itself, the address of the pointer variable, using &p, but we can't do it with an array. Using &myarray will give back the address of the first element again.
This means that you can assign myarray address to p, but not the reverse ;-)
I'm running Xcode 7.1 on Mac OS X 10.11. I'm trying to declare a VLA array in C but I can't do it.
The second I use a variable in the array declaration, it's moot. The array doesn't get created. I've dug around in the compiler settings, tried installing GCC manually, I can't figure this out. Can anyone spot the issue? From what I understand VLA's became standard since C99 and from what I can tell my Xcode is running on C11. What is the deal here? Code and settings images included.
void printTriangle (int height, char rowPatterns[][height]) {
int rowSize = 2 * height - 1;
char rowString[rowSize]; //string to store in pattern's array
int characterCount = rowSize; //number of character printed per row of triangle
int asteriskCount = 1; //number of asterisks printed in each row
int spaces = (characterCount - asteriskCount) / 2; //how many spaces need to be printed in this current row
int rowCount;
// rest of the code...
}
A VLA, like any other local variable, is probably not even allocated before the moment you use it for the first time. Modern compilers do not necessarily allocate local variables at the point of declaration, most often they don't. Therefore, attempting to view the contents of a VLA in a debugger just after the point of declaration is not meaningful.
We had a school project, any information system using C. To keep a dynamic-sized list of student records, I went for a linked list data structure. This morning my friend let me see his system. I was surprised with his list of records:
#include <stdio.h>
/* and the rest of the includes */
/* global unsized array */
int array[];
int main()
{
int n;
for (n=0; n < 5; n ++) {
array[n] = n;
}
for (n=0; n < 5; n ++) {
printf("array[%d] = %d\n", n, array[n]);
}
return 0;
}
As with the code, he declared an unsized array that is global (in the bss segment) to the whole program. He was able to add new entries to the array by overwriting subsequent blocks of memory with a value other than zero so that he can traverse the array thusly:
for (n=0; array[n]; n++) {
/* do something */
}
He used (I also tested it with) Turbo C v1. I tried it in linux and it also works.
As I never encountered this technique before, I am presuming there is a problem with it. So, yeah, I wanna know why this is a bad idea and why prefer this over a linked list.
int array[];
Is technically known as an array with incomplete type. Simply put it is equivalent to:
int array[1];
This is not good simply because:
It produces an Undefined behavior. The primary use of array with incomplete type is in Struct Hack. Note that incomplete array types where standardized in C99 and they are illegal before.
This is Undefined behaviour. You are writing to unallocated memory (beyond the array). In order to compile this, the compiler is allocating at least one element, and you're then writing beyond that. Try a much bigger range of numbers. For example, if I run your code on Linux it works, but if I change the loop to 50,000, it crashes.
EDIT The code may work for small values of n but for larger values it will fail. To demonstrate this I've written your code and tested it for n = 1000.
Here is the link for CODEPAD, and you can see that for n = 1000, a segmentation fault happens.
Whereas with the same code with the same compiler, it is working for n = 10, see this link CODEPAD. So this is called Undefined behavior.
If you use linked lists you can check whether the memory is allocated properly or not.
int *ptr;
ptr = (int *)malloc(sizeof(int))
if(ptr==NULL)
{
printf("No Memory!!!");
}
But with your code the program simply crashes if tested with an array having a large bound.
Why does the array a not get initialized by global variable size?
#include<stdio.h>
int size = 5;
int main()
{
int a[size] = {1, 2, 3, 4, 5};
printf("%d", a[0]);
return 0;
}
The compilation error is shown as
variable-sized object may not be initialized
According to me, the array should get initialized by size.
And what would be the answer if I insist on using global variable (if it is possible)?
In C99, 6.7.8/3:
The type of the entity to be
initialized shall be an array of
unknown size or an object type that is
not a variable length array type.
6.6/2:
A constant expression can be evaluated
during translation rather than runtime
6.6/6:
An integer constant expression
shall have integer type and shall only
have operands that are integer
constants, enumeration constants,
character constants, sizeof
expressions whose results are integer
constants, and floating constants that
are the immediate operands of casts.
6.7.5.2/4:
If the size is an integer constant
expression and the element type has a
known constant size, the array type is
not a variable length array type;
otherwise, the array type is a
variable length array type.
a has variable length array type, because size is not an integer constant expression. Thus, it cannot have an initializer list.
In C90, there are no VLAs, so the code is illegal for that reason.
In C++ there are also no VLAs, but you could make size a const int. That's because in C++ you can use const int variables in ICEs. In C you can't.
Presumably you didn't intend a to have variable length, so what you need is:
#define size 5
If you actually did intend a to have variable length, I suppose you could do something like this:
int a[size];
int initlen = size;
if (initlen > 5) initlen = 5;
memcpy(a, (int[]){1,2,3,4,5}, initlen*sizeof(int));
Or maybe:
int a[size];
for (int i = 0; i < size && i < 5; ++i) {
a[i] = i+1;
}
It's difficult to say, though, what "should" happen here in the case where size != 5. It doesn't really make sense to specify a fixed-size initial value for a variable-length array.
You don't need to tell the compiler what size the array is if you're giving an initializer. The compiler will figure out the size based on how many elements you're initializing it with.
int a[] = {1,2,3,4,5};
Then you can even let the compiler tell you the size by getting the total size of the array in bytes sizeof(a) and dividing it by the size of one element sizeof(a[0]):
int size = sizeof(a) / sizeof(a[0]);
The compiler cannot assume that the value of size is still 5 by the time main() gets control. If you want a true constant in an old-style C project, use:
#define size 5
size is a variable, and C does not allow you to declare (edit: C99 allows you to declare them, just not initialize them like you are doing) arrays with variable size like that. If you want to create an array whose size is a variable, use malloc or make the size a constant.
It looks like that your compiler is not C99 Compliant...speaking of which, which compiler are you using? If it's gcc you need to pass the switch '-std=c99'.... if you are using a pre-C99 compiler, that statement is illegal, if that's the case, do this:
int main() {
int a[5]={1,2,3,4,5};
printf("%d",a[0]);
return 0;
}
In pre-C99 standard compilers, use a constant instead of a variable.
Edit: You can find out more about the C99 standard here... and here....
The compiler needs to know the size of the array while declaring it.
Because the size of an array doesn't change after its declaration.
If you put the size of the array in a variable, you can imagine that the value of that variable will change when the program is executed.
In this case, the compiler will be forced to allocate extra memory to this array.
In this case, this is not possible because the array is a static data structure allocated on the stack.
I hope that this will help.
#include<stdio.h>
/* int size=5; */
#define size 5 /* use this instead*/
/*OR*/
int a[size]={1,2,3,4,5}; /* this*/
int main()
{
int a[size]={1,2,3,4,5};
printf("%d",a[0]);
return 0;
}
int size means that size is a variable and C does not allow variablesize arrays.
I am using VS2008 where using
const int size=5;
allows
int a[size]={1,2,3,4,5};
You cannot create arrays with globally variable size the same reason why you cannot create an array with size determined by a variable in general. The reason is because C++ enables manual memory management, which let's be honest is the reason why we learn this language, and when we allocate memory, we need to keep in mind the advantages and drawbacks of its two types and what we can do with it.
Stack memory literally implements the stack data structure. It has fixed size (a few megabytes as far as I know), and when you put any data on the stack, you push it to the top. Stack fits perfectly for scoped variables that are supposed to only live for a restricted amount of time, which means it will disappear as soon as they see }. Stacks use functions as a unit of grouping all variables, and whenever we call any function (including main), it pushes the total amount of memory this function uses, which is the sum of all variables it allocates. This total size is called stack frame, and it must be constant. Otherwise, if we allocate an array dynamically on the stack:
int size;
scanf("%d", %size);
int array[size];
We don't know how much space we need to reserve for the array and its stack frame responsively, which makes this a forbidden operations. You can, however, initialise it with a constant and constant expression:
constexprt int getSize(int n){
return n * 2; //This can be anything, I just multiplied to get arbitrary value.
}
const int size = 45;
int constantArray[size]; //Works
int constantExpressionArray[getSize(2)]; //Also works
The reason why constant works is because they are always assured to have the same and known size, and furthermore they don't take up space in memory but compilers just substitute all constant calls with their respective values. Constant expresions also are functions that are executed in the compile-time, which means all values must be known, and then it just substitudes the result (that must always be the same) into its call, which assure the compiler in both cases the size of the arrays are going to be the same (45 for the first one and 4 for the second one).
If you want to have an array with size that veries each time you execute it, you should either allocate it dynamically:
int* dynamicArray = new int[variableSize];
or use std::vector:
std::vector<int> dynamicArray(variableSize);
In the latter case it sets variableSize to be the capacity,which is the length of the array it needs to exceed to resize. If you use it responsibly, you will end up simply using the array underneath it and will only suffer from the performance penalties imposed by dynamically allocating memory and jumping between the functions.