What do array initialisers return? - c

What do array initialisers such as { 'a', 'b', 'c' } return? My understanding is that using an initialiser allocates contiguous memory blocks and return the address to the first block.
The following code doesn't work:
char *char_ptr_1 = { 'a', 'b', 'c', '\0' };
On the other hand, this is seems to work fine:
char char_array[] = { 'a', 'b', 'c', '\0' };
char *char_ptr_2 = char_array;
char_array stores the address to the first memory block which explains why I am able to assign the value of char_array to chat_ptr_2. Does C convert the value returned by the initialiser to something which can be stored in a pointer?
I did look online and and found a couple of answers which talked about the difference between arrays and pointers but they didn't help me.

Initializers do not return anything per se. They give the compiler directions as to what to put into the item being declared - in this case, they tell the compiler what to put into elements of an array.
That is why you cannot assign an initializer to a pointer: an array initializer needs to be paired with an array to make sense to the compiler.
A pointer can be initialized with a pointer expression. That is why the initialization in your
char *char_ptr_2 = char_array;
declaration works: the compiler converts char_array to a pointer, and initializes char_ptr_2 with it.

it's called array initializer, because it initalizes an array and not a pointer.
It's simply C syntax, why the pointer option is not allowed.

They are array initializers, not normal expressions that have a value. I. e., an array initializer can only be used to initialize an array. It is a special bit of syntax for a specific use, end of the story.

It doesn't really "return" anything, it's parsed compile time and an array is created. A pointer needs to point to something, you cannot assign it a direct value. So you first need the array, and then your pointer can point to it.

Related

Initializing an array with a pointer in c

When I run the code:
char *abc="Goodbye";
for(i=0; i<=7; i++){
printf("%c\n",*(abc+i)); }
it runs without problem, but when I run the following:
char *der={'a','a','a','a','a'};
for(i=0; i<=4; i++){
printf("%c\n",*(der+i)); }
it doesn't show the correct results and I receive warnings.
So why is this happening since "Goodbye" and {'a','a','a','a','a'} are arrays of chars?
{'a','a','a','a','a'} is not an array but an initializer list, and it can be used to initialize either an aggregate or a scalar.
(Yes, int x = {'a'}; is valid.)
If it's used to initialize a scalar, such as a pointer, only the first value is used, so your declaration of der is equivalent to
char *der = 'a';
You can probably see what the problem is.
So today's programming lessons:
When your compiler warns you that something might be wrong, it probably is.
(Most experienced programmers treat warnings as errors, -Werr. It's an even more important habit for the inexperienced.)
If you don't understand what a warning means, don't do anything until you've found out.
One way to initialize the array - which is related to your second example - is by doing:
char foo[] = {'a', 'b', 'c'};
In this syntax, to the right side of = you provide the array elements as comma separeted values inside a { }. So in the above example, array foo has three elements. First is a, second is b, and third is c. If you wanted a \0 at the end, you need to do it explicitly as char foo[] = {'a', 'b', 'c', '\0'};.
Regarding your second example, answer by #molbdnilo already explains what is semantically wrong with your statment char *der={'a','a','a','a','a'};. If you want to define der as array and initialize it using { }, you can do:
char der[] = {'a','a','a','a','a'};
This way you are actually defining a char array and initializing it with the content you want.
Note that, you NEED to mention the array size if you are not initializing it while defining it. Which means:
char foo[]; // Will give error because no size is mentioned
char foo[10]; // Fine because size is given as 10
However, mentioning size is optional if you initialize the array while defining it, as we saw in the examples above. But, if you mention the size and if your initializer is smaller than the array size, remaining elements will be initialized to 0. Like:
char bar[10] = {'a', 'b', 'c', '\0'};
/* Your arrays' content will be 'a', 'b', 'c', '\0',
* and all remaning 6 elements will be 0
*/

Returning array declared in function returns address of local variable in C?

I realize that variables declared in a function call are pushed onto the stack and once the function reaches its end the local variables declared onto the stack are popped off and go into lala land.
The thing I don't undertstand is that if I declare a pointer in a function I can return the pointer with no compiler complaint, whereas with an array it does give me a warning.
Here is an example of what I'm referring to:
char * getStringArray();
char * getStringPointer();
int main(){
char * temp1 = getStringPointer();
char * temp2 = getStringArray();
return 0;
}
char * getStringPointer(){
char * retString = "Fred";
return retString;
}
char * getStringArray(){
char retString[5] = {'F', 'r','e','d','\0'};
return retString;
}
During compilation it throws a "returning address of local variable" warning about getStringArray(). What confuses me is that I've been told that referencing an array solely by its name(like retString, no[])refers to its address in memory, acting like a pointer.
Arrays can be handy and there are many times I would like to use an array in a function and return it, is there any quick way around this?
As I referred to in a comment, will this work? I'm guessing malloc allocates to heap but so its fine. I'm still a little unclear of the difference between static data and data on the heap.
char * getStringPointer(){
char * retString = (char *)malloc(sizeof(char)*4+1);
*(retString+0) = 'F';
*(retString+1) = 'r';
*(retString+2) = 'e';
*(retString+3) = 'd';
*(retString+4) = '\0';
return retString;
}
getStringPointer is allocating a pointer on the stack, then returning that pointer, which points to the string 'Fred\0' somewhere in your executable (not on the stack).
getStringArray allocates space for 5 chars on the stack, assigns them 'F' 'r' 'e' 'd' and '\0', then returns a pointer to the address of 'F', which is on the stack (and therefore invalid after the function returns).
There are two ways round it: either you can malloc some space for your array on the heap, or you can make a struct that contains an appropriately sized array and return that. You can return numerical, pointer and struct types from functions, but not arrays.
"Fred" is an unnamed global, so it's not going away, and returning a pointer to it is safe. But getStringArray() is de-allocating everything that pointer points to. That's the difference.
The array is unambiguously a pointer to stack-local memory so the compiler is certain that's what you are leaking, so that's why you get the warning.
Just make the array static and both the warning and the lifetime restriction will vanish.
Now, the pointer could be pointing to something static or in the heap (in your case it actually was static) and so it's not obvious from looking at just that one expression whether you are leaking something stack-local or not. That's why you don't get the warning when you return a pointer, regardless of whether it's a safe return or not. Again, the static storage class will save you. Your string constant happens to be static, so that works fine.
By adding a static modifier to the variable retString and returning back a pointer will resolve the issue.
char * getStringArray(){
static char retString[5] = {'F', 'r','e','d','\0'};
return retString;
}
That will return the appropriate value.
Notice how its still treated as a pointer, because the first element of the array is decayed into a pointer of type T, in this case, char. This will make the compiler happy as it matches the prototype declaration of the function itself as defined at the start of the source.
See ideone sample

Differences between arrays, pointers and strings in C

Just have a question in mind that troubles me.
I know pointers and arrays are different in C because pointers store an address while arrays store 'real' values.
But I'm getting confused when it comes to string.
char *string = "String";
I read that this line does several things :
An array of chars is created by the compiler and it has the value String.
Then, this array is considered as a pointer and the program assigns to the pointer string a pointer which points to the first element of the array created by the compiler.
This means, arrays are considered as pointers.
So, is this conclusion true or false and why ?
If false, what are then the differences between pointers and arrays ?
Thanks.
A pointer contains the address of an object (or is a null pointer that doesn't point to any object). A pointer has a specific type that indicates the type of object it can point to.
An array is a contiguous ordered sequence of elements; each element is an object, and all the elements of an array are of the same type.
A string is defined as "a contiguous sequence of characters terminated by and including the first null character". C has no string type. A string is a data layout, not a data type.
The relationship between arrays and pointers can be confusing. The best explanation I know of is given by section 6 of the comp.lang.c FAQ. The most important thing to remember is that arrays are not pointers.
Arrays are in a sense "second-class citizens" in C and C++. They cannot be assigned, passed as function arguments, or compared for equality. Code that manipulates arrays usually does so using pointers to the individual elements of the arrays, with some explicit mechanism to specify how long the array is.
A major source of confusion is the fact that an expression of array type (such as the name of an array object) is implicitly converted to a pointer value in most contexts. The converted pointer points to the initial (zeroth) element of the array. This conversion does not happen if the array is either:
The operand of sizeof (sizeof array_object yields the size of the array, not the size of a pointer);
The operand of unary & (&array_object yields the address of the array object as a whole); or
A string literal in an initializer used to initialize an array object.
char *string = "String";
To avoid confusion, I'm going to make a few changes in your example:
const char *ptr = "hello";
The string literal "hello" creates an anonymous object of type char[6] (in C) or const char[6] (in C++), containing the characters { 'h', 'e', 'l', 'l', 'o', '\0' }.
Evaluation of that expression, in this context, yields a pointer to the initial character of that array. This is a pointer value; there is no implicitly created pointer object. That pointer value is used to initialize the pointer object ptr.
At no time is an array "treated as" a pointer. An array expression is converted to a pointer type.
Another source of confusion is that function parameters that appear to be of array type are actually of pointer type; the type is adjusted at compile time. For example, this:
void func(char param[10]);
really means:
void func(char *param);
The 10 is silently ignored. So you can write something like this:
void print_string(char s[]) {
printf("The string is \"%s\"\n", s);
}
// ...
print_string("hello");
This looks like just manipulating arrays, but in fact the array "hello" is converted to a pointer, and that pointer is what's passed to the print_string function.
So, is this conclusion true or false and why ?
Your conclusion is false.
Arrays and pointers are different. comp.lang.c FAQ list ยท Question 6.8 explains the difference between arrays and pointers:
An array is a single, preallocated chunk of contiguous elements (all of the same type), fixed in size and location. A pointer is a reference to any data element (of a particular type) anywhere. A pointer must be assigned to point to space allocated elsewhere, but it can be reassigned (and the space, if derived from malloc, can be resized) at any time. A pointer can point to an array, and can simulate (along with malloc) a dynamically allocated array, but a pointer is a much more general data structure.
When you do
char *string = "String";
and when a C compiler encounters this, it sets aside 7 bytes of memory for the string literal String. Then set the pointer string to point to the starting location of the allocated memory.
When you declare
char string[] = "String";
and when a C compiler encounters this, it sets aside 7 bytes of memory for the string literal String. Then gives the name of that memory location, i.e. the first byte, string.
So,
In first case string is a pointer variable and in second case it is an array name.
The characters stored in first case can't be modified while in array version it can be modified.
This means arrays is not considered as pointers in C but they are closely related in the sense that pointer arithmetic and array indexing are equivalent in C, pointers and arrays are different.
You have to understand what is happening in memory here.
A string is a contiguous block of memory cells that terminates with a special value (a null terminator). If you know the start of this block of memory, and you know where it ends (either by being told the number of memory cells or by reading them until you get to the null) then you're good to go.
A pointer is nothing more than the start of the memory block, its the address of the first memory cell, or its a pointer to the first element. All those terms mean the same thing. Its like a cell reference in a spreadsheet, if you have a huge grid you can tell a particular cell by its X-Y co-ordinates, so cell B5 tells you of a particular cell. In computer terms (rather than spreadsheets) memory is really a very, very long list of cells, a 1-dimensional spreadsheet if you like, and the cell reference will look like 0x12345678 rather than B5.
The last bit is understanding that a computer program is a block of data that is loader by the OS into memory, the compiler will have figured out the location of the string relative to the start of the program, so you automatically know which block of memory it is located in.
This is exactly the same as allocating a block of memory on the heap (its just another part of the huge memory space) or the stack (again, a chunk of memory reserved for local allocations). You have the address of the first memory location where your string lives.
So
char* mystring = "string";
char mystring[7];
copy_some_memory(mystring, "string", 7);
and
char* mystring = new char(7);
copy_some_memory(mystring, "string", 7);
are all the same thing. mystring is the memory location of the first byte, that contains the value 's'. The language may make them look different, but that's just syntax. So an array is a pointer, its just that the language makes it look different, and you can operate on it with slightly different syntax designed to make operations on it safer.
(note: the big difference between the 1st and other examples is that the compiler-set set of data is read-only. If you could change that string data, you could change your program code, as it too it just a block of CPU instructions stored in a section of memory reserved for program data. For security reasons, these special blocks of memory are restricted to you).
Here's another way to look at them:
First, memory is some place you can store data.
Second, an address is the location of some memory. The memory referred to by the address may or may not exist. You can't put anything in an address, only at an address - you can only store data in the memory the address refers to.
An array is contiguous location in memory - it's a series of memory locations of a specific type. It exists, and can have real data put into it. Like any actual location in memory, it has an address.
A pointer contains an address. That address can come from anywhere.
A string is a NUL-terminated array of characters.
Look at it this way:
memory - A house. You can put things in it. The house has an address.
array - A row of houses, one next to the other, all the same.
pointer - a piece of paper you can write an address on. You can't store anything in the piece of paper itself (other than an address), but you can put things into the house at the address you write on the paper.
We can create an array with the name 'string'
char string[] = "Hello";
We can allocate a pointer to that string
char* stringPtr = string;
The array name is converted to a pointer
So, an array name is similar to the pointer. However, they're not the same, as the array is a contiguous block of memory, whereas the pointer references just a single location (address) in memory.
char *string = "String";
This declaration creates the array and sets the address of the pointer to the block of memory used to store the array.
This means, arrays are considered as pointers. So, is this conclusion true or false
False, arrays are not pointers. However, just to confuse(!), pointers can appear to be arrays, due to the dereference operator []
char *string = "String";
char letter = string[2];
In this case string[2], string is first converted to a pointer to the first character of the array and using pointer arithmetic, the relevant item is returned.
Then, this array is considered as a pointer and the program assigns to the pointer string a pointer which points to the first element of the array created by the compiler.
Not really great wording here. Array is still an array and is considered as such. The program assigns a pointer-to-first-element value (rvalue) to pointer-to-char variable (lvalue in general). That is the only intermediate/non-stored pointer value here, as compiler and linker know array's address at compile-link time. You can't directly access the array though, because it is anonymous literal. If you were instead initializing an array with literal, then literal would disappear (think like optimized-out as separate entity) and array would be directly accessible by its precomputed address.
char s[] = "String"; // char[7]
char *p = s;
char *p = &s[0];

Array syntax and pointers in C

Is my understanding of arrays in C correct?
Arrays are nothing more than a syntactic convenience such that, for instance, when you declare in your C code an array:
type my_array[x];
the compiler sees it as something equivalent to:
type *my_array = malloc(sizeof(*my_array) * x);
with a free system call that releases my_array once we leave the scope of my_array.
Once my_array is declared
my_array[y];
is nothing more but:
*(my_array + y)
Transposing this to character strings; I was also wondering what was happening behind the curtain with
char *my_string = "Hello"
and
my_string = "Hello"
No, an array object is an array object. C has some odd rules that make it appear that arrays and pointers are the same thing, or at least very similar, but they very definitely are not.
This declaration:
int my_array[100];
creates an array object; the object's size is 100 * sizeof (int). It does not create a pointer object.
There is no malloc(), even implicitly. Storage for my_array is allocated the same way as storage for any object declared in the same scope.
What may be confusing you is that, in most but not all contexts, an expression of array type is implicitly converted to a pointer to the array's first element. (This gives you a pointer value; there's still no pointer object.) This conversion doesn't happen if the array expression is the operand of a unary & or sizeof. &my_array gives you the address of the array, not of some nonexistent pointer obejct. sizeof my_array is the size of the entire array (100 * sizeof (int)`), not the size of a pointer.
Also, if you define a function parameter with an array type:
void func(int param[]) { ... }
it's adjusted at compile time to a pointer:
void func(int *param) { ... }
This isn't a conversion; in that context (and only in that context), int param[] really means int *param.
Also, array indexing:
my_array[3] = 42;
is defined in terms of pointer arithmetic -- which means that the prefix my_array has to be converted to a pointer before you can index into it.
The most important thing to remember is this: Arrays are not pointer. Pointers are not arrays.
Section 6 of the comp.lang.c FAQ explains all this very well.
Once my_array is declared
my_array[y];
is nothing more but :
*(my_array + y)
Yes, because my_array is converted to a pointer, and the [] operator is defined so that x[y] means *(x+y).
Transposing this to character strings; i was also wondering what was
happening behind the curtain with
char *my_string = "Hello"
and
my_string = "Hello"
"Hello" is a string literal. It's an expression of type char[6], referring to an anonymous statically allocated array object. If it appears on the RHS of an assignment or initializer, it's converted, like any array expression, to a pointer. The first line initializes my_string so it points to the first character of "Hello". The second is a pointer assignment that does the same thing.
So what about this?
char str[] = "Hello";
This is the third context in which array-to-pointer conversion doesn't happen. str takes its size from the size of the string literal, and the array is copied to str. It's the same as:
char str[] = { 'H', 'e', 'l', 'l', 'o', '\0' };
No!
type array[n] is a variable stored on stack
type *array is a pointer variable stored on the stack too. But after array = malloc(sizeof(*array) * n); it'll point to some data on the heap
If it walks like a duck, swims like a duck and flies like a duck, then it is a duck.
So, let's see. Arrays and pointers have some common attributes as you correctly described, however, you can see there are some differences. Read more here.

C: Behaviour of arrays when assigned to pointers

#include <stdio.h>
main()
{
char * ptr;
ptr = "hello";
printf("%p %s" ,"hello",ptr );
getchar();
}
Hi, I am trying to understand clearly how can arrays get assign in to pointers. I notice when you assign an array of chars to a pointer of chars ptr="hello"; the array decays to the pointer, but in this case I am assigning a char of arrays that are not inside a variable and not a variable containing them ", does this way of assignment take a memory address specially for "Hello" (what obviously is happening) , and is it possible to modify the value of each element in "Hello" wich are contained in the memory address where this array is stored. As a comparison, is it fine for me to assign a pointer with an array for example of ints something as vague as thisint_ptr = 5,3,4,3; and the values 5,3,4,3 get located in a memory address as "Hello" did. And if not why is it possible only with strings? Thanks in advanced.
"hello" is a string literal. It is a nameless non-modifiable object of type char [6]. It is an array, and it behaves the same way any other array does. The fact that it is nameless does not really change anything. You can use it with [] operator for example, as in "hello"[3] and so on. Just like any other array, it can and will decay to pointer in most contexts.
You cannot modify the contents of a string literal because it is non-modifiable by definition. It can be physically stored in read-only memory. It can overlap other string literals, if they contain common sub-sequences of characters.
Similar functionality exists for other array types through compound literal syntax
int *p = (int []) { 1, 2, 3, 4, 5 };
In this case the right-hand side is a nameless object of type int [5], which decays to int * pointer. Compound literals are modifiable though, meaning that you can do p[3] = 8 and thus replace 4 with 8.
You can also use compound literal syntax with char arrays and do
char *p = (char []) { "hello" };
In this case the right-hand side is a modifiable nameless object of type char [6].
The first thing you should do is read section 6 of the comp.lang.c FAQ.
The string literal "hello" is an expression of type char[6] (5 characters for "hello" plus one for the terminating '\0'). It refers to an anonymous array object with static storage duration, initialized at program startup to contain those 6 character values.
In most contexts, an expression of array type is implicitly converted a pointer to the first element of the array; the exceptions are:
When it's the argument of sizeof (sizeof "hello" yields 6, not the size of a pointer);
When it's the argument of _Alignof (a new feature in C11);
When it's the argument of unary & (&arr yields the address of the entire array, not of its first element; same memory location, different type); and
When it's a string literal in an initializer used to initialize an array object (char s[6] = "hello"; copies the whole array, not just a pointer).
None of these exceptions apply to your code:
char *ptr;
ptr = "hello";
So the expression "hello" is converted to ("decays" to) a pointer to the first element ('h') of that anonymous array object I mentioned above.
So *ptr == 'h', and you can advance ptr through memory to access the other characters: 'e', 'l', 'l', 'o', and '\0'. This is what printf() does when you give it a "%s" format.
That anonymous array object, associated with the string literal, is read-only, but not const. What that means is that any attempt to modify that array, or any of its elements, has undefined behavior (because the standard explicitly says so) -- but the compiler won't necessarily warn you about it. (C++ makes string literals const; doing the same thing in C would have broken existing code that was written before const was added to the language.) So no, you can't modify the elements of "hello" -- or at least you shouldn't try. And to make the compiler warn you if you try, you should declare the pointer as const:
const char *ptr; /* pointer to const char, not const pointer to char */
ptr = "hello";
(gcc has an option, -Wwrite-strings, that causes it to treat string literals as const. This will cause it to warn about some C code that's legal as far as the standard is concerned, but such code should probably be modified to use const.)
#include <stdio.h>
main()
{
char * ptr;
ptr = "hello";
//instead of above tow lines you can write char *ptr = "hello"
printf("%p %s" ,"hello",ptr );
getchar();
}
Here you have assigned string literal "hello" to ptr it means string literal is stored in read only memory so you can't modify it. If you declare char ptr[] = "hello";, then you can modify the array.
Say what?
Your code allocates 6 bytes of memory and initializes it with the values 'h', 'e', 'l', 'l', 'o', and '\0'.
It then allocates a pointer (number of bytes for the pointer depends on implementation) and sets the pointer's value to the start of the 5 bytes mentioned previously.
You can modify the values of an array using syntax such as ptr[1] = 'a'.
Syntactically, strings are a special case. Since C doesn't have a specific string type to speak of, it does offer some shortcuts to declaring them and such. But you can easily create the same type of structure as you did for a string using int, even if the syntax must be a bit different.

Resources