It appears that I don't practically know the difference between
char *(arr[5]) and char (*arr)[5]
Logically, as it is with type-definitions, char *(arr[5]) is a pointer to an array of 5 char's, char *arr[5] is an array of char pointers then what (*arr)[5] will be then? Or it makes no difference ?
I did some tests and found out that these 3 declarations are different.
For instance if I use char (*arr)[5] it totally allows me to do that arr = malloc(2), otherwise it moans about illegal conversions.
Can someone explain the differences between these declarations, when they are used and it will be a huge plus if this also includes may I do arr = malloc(2) to dynamically allocate an array of [5] chars, as it allows me to semantically do so with char (*arr)[5] although giving me stack overflows when being used. (disclaimer: [] suggests stack allocation, so it doesn't make much sense as a heap memory address cannot point to stack memory address as far as I am not aware)
char *(arr[5]) equals to char *arr[5] and it means you have array of pointers that each of them points to a character so arr[0] can points to a character and arr[1] can points to a character and so on.
For example you can write your code like this:
char *(arr[5]);// or char *arr[5]
char a = 'a',b='b',c='c';
arr[0] = &a;
arr[1] = &b;
arr[2] = &c;
printf("a=%c b=%c c=%c \n",*arr[0],*arr[1],*arr[2]);
But (*arr)[5] means you have an array of 5 characters and you want to point it.
For example you can write your code like this:
char (*arr)[5];
char str[5] = "Hell";
arr = &str;
printf("%s\n",*arr);
Related
I'm new to C and have a trouble understanding pointers. The part that I'm confused is about char * and int *.
For example, we can directly assign a pointer for char, like
char *c = "c"; and it doesn't make errors.
However, if I assign a pointer for int like I just did, for example int * a = 10;,
it makes errors. I need to make an additional space in memory to assign a pointer for int,
like int *b = malloc(sizeof(int)); *b = 20; free(b);...
Can anyone tell me why?
I think you're misunderstanding what a pointer is and what it means. In this case:
int* a = 10;
You're saying "create a pointer (to an int) and aim it at the literal memory location 0x0000000A (10).
That's not the same as this:
int n = 10;
int* a = &n;
Which is "create a pointer (to an int) and aim it at the memory location of n.
If you want to dynamically allocate this:
int* a = malloc(sizeof(int));
*a = 10;
Which translates to "create a pointer (to an int) and aim it at the block of memory just allocated, then assign to that location the value 10.
Normally you'd never allocate a single int, you'd allocate a bunch of them for an array, in which case you'd refer to it as a[0] through a[n-1] for an array of size n. In C *(x + y) is generally the same as x[y] or in other words *(x + 0) is either just *x or x[0].
In your example, you do not send c to the char 'c'. You used "c" which is a string-literal.
For string-literals it works as explained in https://stackoverflow.com/a/12795948/5280183.
In initialization the right-hand side (RHS) expression must be of or convertible to the type of the variable declared.
If you do
char *cp = ...
int *ip = ...
then what is in ... must be convertible to a pointer to a char or a pointer to an int. Also remember that a char is a single character.
Now, "abc" is special syntax in C - a string literal, for creating an array of (many) immutable characters. It has the type char [size] where size is the number of characters in the literal plus one for the terminating null character. So "c" has type char [2]. It is not char. An array in C is implicitly converted to pointer to the first element, having then the type "pointer to the element type". I.e. "c" of type char [2] in char *cp = "c"; is implicitly converted to type char *, which points to the first of the two characters c and \0 in the two-character array. It is also handily of type char * and now we have char *cp = (something that has type char * after conversions);.
As for int *, you're trying to pass an integer value to a pointer. It does not make sense.
A pointer holds an address. If you'd ask for the address of Sherlock Holmes, the answer would be 221 Baker Street. Now instead what you've done is "address of Sherlock Holmes is this photo I took of him in this morning".
The same incorrect code written for char * would be
char *cp = 'c'; // or more precisely `char *p = (char)'c';
and it would give you precisely the same error proving that char *cp and int *cp work alike.
Unfortunately C does not have int string literals nor literals for integer arrays, though from C99 onwards you could write:
int *ip = (int[]){ 5 };
or
const int *ip = (const int[]){ 5 };
Likewise you can always point a char * or int * to a single object of that type:
char a = 'c';
char *pa = &a;
int b = 42;
int *pb = &b;
now we can say that a and *pa designate the same char object a, and likewise b and *pb designate the same int object b. If you change *pa you will change a and vice versa; and likewise for b and *pb.
A string literal like "c" is actually an array expression (the type of "c" is "2-element array of char).
Unless it is the operand of the sizeof or & operators, or is a string literal used to initialize a character array in a declaration, an expression of type "array of T" will be converted, or "decay" to an expression of type "pointer to T" and its value will be the address of the first element of the array.
So when you write
char *c = "c";
it’s roughly equivalent to writing
char string[] = "c";
char *c = &string[0];
You’re assigning a pointer to a pointer, so the compiler doesn’t complain.
However, when you write
int *a = 10;
you’re assigning an int value to a pointer and the types are not compatible, so the compiler complains. Pointers are not integers; they may have an integer representation, but that’s not guaranteed, and it won’t be the same size as int.
Are there differences between int pointer and char pointer in c?
short answer: NO
All pointers in C are created equal in the last decades. During some time there were pointers of different sizes, in some platforms like Windows, due to a thing called memory model.
Today the compiler sets the code to use 32-bit or 64 or any size pointers depending on the platform, but once set all pointers are equal.
What is not equal is the thing a pointer points to, and it is that you are confused about.
consider a void* pointer. malloc() allocates memory in C. It always return a void* pointer and you then cast it to anything you need
sizeof(void*) is the same as sizeof(int*). And is the same as sizeof(GiantStruct*) and in a 64-bit compiler is 8 bytes or 64 bits
what about char* c = "c"?
you must ask yourself what is "c". is is char[2]. And it is a string literal. Somewhere in memory the system will allocate an area of at least 2 bytes, put a 'c' and a zero there, since string literals are NULL terminated in C, take that address in put in the address allocated to your pointer c.
what about int* a = 10?
it is the same thing. It is somewhat ok until the operating system comes in. What is a? a is int* pointer to an int. And what is *a? an int. At which address? 10. Well, truth is the system will not let you access that address just because you set a pointer to point to it. In the '80s you could. Today there are very strong rules on this: you can only access memory allocated to your processes. Only. So the system aborts your program as soon as you try to access.
an example
if you write
int* a = malloc(300);
the system will allocate a 300-bytes area, take the area address and write it for you at the address allocated to a. When you write *a=3456 the system will write this value to the first sizeof(int) bytes at that address.
You can for sure write over all 300, but you must somewhat manipulate the pointer to point inside the area. Only inside that area.
In fact C language was designed just for that.
Let us write "c" to the end of that 300-byte area alocated to a:
#include <stdio.h>
#include <stdlib.h>
int main(void)
{
char* c = "c";
int* a = (int*)malloc(300);
*a = 3456;
printf("Area content is %d\n", *a);
char* pToEnd = (char*)a + 298;
*(pToEnd) = 'c';
*(pToEnd + 1) = 0;
printf("At the end of the 300-byte area? [Should be 'c'] '%s'\n", pToEnd);
printf("The pointer c points to '%s'\n", c);
//*c = 'x'; // error: cancel program
c = pToEnd;
printf("The pointer c now points do the end of the 300-byte area:'%s'\n", c);
free(a);
return 0;
};
and see
Area content is 3456
At the end of the 300-byte area? [Should be 'c'] 'c'
The pointer c points to 'c'
The pointer c now points do the end of the 300-byte area:'c'
Also note that as soon as you try to write over c, the char pointer in your example, your program will also cancel. It is a read only area --- see the comment on line 14. But you can point c inside the area in the example and use it, since the pointer in itself is not constant.
And when you write c = pToEnd in the example above access to the string literal is lost forever. In some sense is a memory leak, but it is a static allocated area. The leak is not the area but the address.
Note also that free(a) at the end, even if being a int* will free all 300 bytes
The direct answer to your question, is that, C language is a strict typed language. And before the machine code is produced, a compiler checks for some possible errors. The types are different, and that is all that the compiler wants to know.
But from the bit-byte point of view, there are no difference, for C language, with the above two pointers.
Take a look at your code with online compiler
void main(){
int * a = 10; /* <= this presumably gives you an error. */
}
What I did is copy pasted your code that gives you the error. And online compiler had emitted a warning, not an error. Even more than that. Change the C standard to be of c17 and you still get a mere warning.
The note about assigning a string literal to a pointer had been discussed broadly at SO. It deserves a different topic.
To sum it up. For the C language there is no meaningful difference in the above two pointers. It is a user, who takes a responsibility to know a layout of a memory in his/her program. All in all, the language was designed as a high level tool that operates over linear memory.
This question already has answers here:
What is array to pointer decay?
(11 answers)
Closed 2 years ago.
When we want to have a pointer for integer we add &(int *p = &n)
int n=50;
int *p = &n;
, so similarly in case of a string shouldn't it be the same as this,
char name[] = "Hello"
char *s = &name;
or like this code below,
char *s= &"Hello";
rather than like this,
char *s= "Hello";
OR
char name[] = "Hello";
char *ptr=name;
OR
char name[] = "Hello";
char *ptr;
ptr= name;
I don't think the last two codes are different.
In this version:
int n = 50;
int *p = &n;
you have a single int n. To make a pointer to it, you need to take its address with &.
On the other hand, in this version:
int n[50];
int *p = n;
the variable n is an array of int. This has the property that the name of the array actually refers to the first element (i.e. the array decays to a pointer when used like this). So no & is needed to refer to the address.
The exact same logic applies to the char case:
char name[] = "Hello";
char *ptr = name;
where name is an array, so you can take a pointer to the first element by just using the variable name without using &.
char *s = &name; does not work because the pointer types do not match. When you apply the "address of" operator to an array, what you get is a pointer to an array. But the pointer variable that you are initialising is not a pointer to an array. It is a pointer to a char.
You can use the exactly same pattern that you used with integer to get a pointer to an array:
char (*s)[6] = &name;
Alternatively, when you want a pointer to an element of an array, you can use the subscript operator to get the element, and apply addressof on that element:
char *s = &name[0];
But char *s = name; also works because the array implicitly converts to pointer to first element. This implicit conversion is called decaying.
Given char name[] = "Hello";, if you want the address of name, you should use &name. That provides a pointer to an array of six char.
The compiler should warn about char *s = &name; because it uses a pointer to an array for a pointer to a char, and those are different (and incompatible) types of pointers.
In C, we generally do not work with arrays. Instead, we work with pointers to array elements. To assist with this, C automatically converts an array to a pointer to its first element, except in certain situations.
Thus char *s = name;, name is automatically converted to a pointer to its first element, which is a char. This is the reason we do not need to use & with arrays, even though we need to use & to take the address of a non-array—with an array, C automatically gives us an address, so we do not need to use &.
Although &name points to the start of the array and name points (after conversion) to the first character of the array, which starts in the same place, the pointers have different types.
This question already has answers here:
What is the difference between char s[] and char *s?
(14 answers)
Closed 3 years ago.
with string literal declaration like this:
char str[] = "hello";
and this
char *ptr = "hello";
initialisation of ptr with str is possible:
ptr = str; //valid
but not viceversa:
str = ptr; //invalid
although str being a char array would hold the address of the first element anyways, then what makes the second case invalid and not the first one?
Here
char str[] = "hello";
char *ptr = str; /* valid */
above pointer assignment char *ptr = str; is valid as ptr is pointer and its assigned with str which points to base address of str, and in this case ptr is not a constant pointer i.e it can point to different memory location, hence it can be assigned like ptr = str.
But in below case
char *ptr = "hello";
char str[10] = ptr; /* invalid */
the statement char str[10] = ptr; is not valid as str name itself represents one address and by doing char str[10] = ptr; you are trying to modify the base address of str which is not possible because array is not a pointer.
At very first, the string "hello" actually is an array located somewhere in (immutable!) memory.
You can assign it to a pointer, which is what you do in second example (char* ptr = ...). In this case, the pointer just points to that immutable array, i. e. holds the array's address. Recommendation at this point: Although legal in C (unlike C++), don't assign string literals to char* pointers, assign them only to char const* pointers; this reflects immutability much better.
In the second example, you use the first array (the literal) to initialise another array (str). This other array str (if not provided explicit length, as in the example) will use the first array's length and copy the contents of. This second array isn't immutable any more and you can modify it (as long as you do not exceed its bounds).
Assignment: Arrays decay to pointers automatically, if the context they are used in requires a pointer. This is why your first assignment example works, you assign a pointer (the one the array decayed to) to another one (ptr). Actually, exactly the same as in your second initialisation example, you don't do anything different there either...
But arrays aren't pointers, and pointers never decay backwards to arrays. This is why the second assignment example doesn't work.
When we create a pointer to int we need to point that pointer to a variable, but when we create a string we only need to point to a word (exemple).
I can't understand why strings can point to values (chars) and other pointers of type int, float can't.
A pointer of to int can point to a value that isn't contained in a variable:
int* p;
p = malloc(sizeof(int));
*p = 5;
The value 5 isn't contained in any variable, but p is pointing to it.
Your question really concerns how pointers are initialized. There is an element of arbitrariness in the way that string literals can initialize a char pointer and array literals can initialize arrays but int literals can't initialize int pointers. Ultimately, that is just the way the language is. With the way that int pointers are typically used (to either pass variables by reference or in dynamic data structures), there really isn't very many natural use-cases for initializing a single int pointer to point to a literal value when declaring it.
char* c = {'H','i','\0'};
is the same as:
char* c = "Hi";
sort of like:
int* a = {0,1,2,3};
is the same as:
int* a = malloc(sizeof(int) * 4);
a[0] = 1;
a[1] = 2;
...
...
A pointer is a reference to a memory location of the type the pointer was declared to point at, in this case a char.
An array of say 10 chars char* c[10]; is 10 continuous memory locations (each the size of 1 char). Here c points to the first location in that continuous memory array. You can randomly access the 10 memory locations using the [] operator. c[0] = 'H'; c[1] = 'i'; or using pointer arithmetic *c = 'H'; c++; *c = 'i';
This may help: http://www.cplusplus.com/doc/tutorial/ntcs/
In C a string literal is not a scalar value but an array of char
I'm confused as to why I can create a string by using just char*. Isn't a char* just a pointer to a single char? What makes me suddenly allowed to treat this thing as a string? Can I do this with other objects? What about:
int* arr;
Do I now have an array of ints? Is it dynamically sized? Can I just start calling
arr[0] and arr[1]
and expect it to work?
I've been googling for quite awhile now, and can't find any clear answer to this question.
This is one part of C I've always just accepted as the way it works...no more.
Pointers point to things. int *arr; currently does not point anywhere. You cannot treat it as pointing to anything (array or otherwise).
You can point it at something. If you point it at a single int, you can treat it as pointing to a single int. If you point it at an element of an array of ints, you can treat it as pointing to an element of an array.
char behaves the same as int (or any other object type) in this respect. You can only treat a char * as pointing to a string if you first point that char * to a string.
Isn't a char* just a pointer to a single char?
It is a pointer to a memory location that should hold a char. It can be a single allocated char, or an array of several char's.
What makes me suddenly allowed to treat this thing as a string?
When the char* pointer points to a memory location where several chars[] are allocated one after another (an array), then you can access them with an array index [idx]. But you have to either:
A. Use a statically allocated array in code:
char myArray[5];
B. or Dynamic allocation (malloc() in C language):
int chars_in_my_array = 10;
char* myArray = (char*)malloc( sizeof(char) * chars_in_my_array );
Can I do this with other objects? What about: int* arr; Do I now have an array of ints?
no you don't:
int* p; //'p' is a *pointer* to an int
int arr[10]; //'arr' is an array of 10 integers in memory.
You can set 'p' to point to the first element in 'arr' by doing this:
p = &arr[0]; //'p' points to the address of the first item in arr[]
Is it dynamically sized?
No. That's something you'd see in a higher-level construct like 'std::string' in C++, or 'String' in Java. In C, memory is managed manually (or you use existing library functions to do this for you. see the standard header file 'string.h')
Can I just start calling arr[0] and arr[1] and expect it to work?
Not unless you do this:
int arr[5];
arr[0] = 100; arr[1] = 200;
...Because you statically allocate an array of five integers. Then you can access them with an array subscript.
However you can NOT do this:
int* p;
p[0] = 100; p[1] = 200; // NO!!
Because 'p' is just a variable that contains a memory address to an integer. It doesn't actually allocate any memory unless you explicitly allocate memory for it. You can do this though:
int* p;
int arr[10];
p = &arr[0];
p[0] = 100; p[1] = 200; // This is OK
This works because 'p' now points to memory that has been (statically) allocated for an array. So we can access the array through the pointer 'p'.
You can also dynamically allocate the array:
int* p;
p = (int*)malloc( sizeof(int) * 10 );
if( p != NULL ) {
p[0] = 100;
p[1] = 200;
}
Here we allocate memory for 10 integers and 'p' points to the first item. Now we can use 'p' as an array. But only for 10 items maximum!
I've been googling for quite awhile now, and can't find any clear
answer to this question. This is one part of C I've always just
accepted as the way it works...no more.
Really? Try googling 'arrays in c', 'memory allocation in C', 'static vs dynamic allocation C', and functions such as malloc() and free(). There's a plethora of information available, but hope this helps for starters :)