char pointers (strings) compared vs other pointers in C - c

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

Related

Are there differences between int pointer and char pointer in c?

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.

why there is no use of & in case of adding pointer to array of character? [duplicate]

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.

Why does '*(veg + i)' work but '*(veg++)' does not? [duplicate]

gcc 4.4.4
What am I doing wrong?
char x[10];
char y[] = "Hello";
while(y != NULL)
*x++ = *y++;
Many thanks for any advice.
x++ is the short form of x = x + 1. However, x here is an array and you cannot modify the address of an array. So is the case with your variable y too.
Instead of trying to increment arrays, you can declare an integer i and increment that, then access the i'th index of an arrays.
char x[10], y[5] = "Hello";
int i = 0;
while (y[i] != 0)
{
x[i] = *y[i];
i++;
}
x[i] = 0;
Most likely you fell victim to a popular misconception that "array is a pointer", i.e. when you define an array what you actually get is an ordinary pointer that points to some block of memory allocated somewhere. In your code you are making an attempt to increment that pointer.
The code does not "work" because in reality arrays are not pointers. Arrays are arrays. Arrays cannot be incremented. There's no such operation as "increment an array" in C language. In fact, arrays by themselves in C are non-modifiable lvalues. There are no operations in C that can modify the array itself (only individual elements can be modifiable).
If you want to traverse your arrays using the "sliding pointer" technique (which is what you are actually trying to do), you need to create the pointers explicitly and make them point to the starting elements of your arrays
char *px = x;
char *py = y;
After that you can increment these pointers as much as you want.
Arrays in C are indeed pointers, but constant pointers, which means after declaration their values can't be changed.
int arr[] = {1, 2, 3};
// arr is declared as const pointer.
(arr + 1) is possible but arr++ is not possible because arr can not store another address since it is constant.
char x[10];
char y[] = "Hello";
char *p_x = &x[0];
char *p_y = &y[0];
while(*p_y != '\0') *p_x++ = *p_y++;
Since you can't modify the array addresses (done by x++ and y++ in your code) and you can modify the pointer address, I copied over the address of the array into separate pointers and then incremented them.
If you want, I'm sure you can reduce the notation, but I hope you got the point.
x and y are arrays, not pointers.
They decay into pointers in most expression contexts, such as your increment expression, but they decay into rvalues, not lvalues and you can only apply increment operators to lvalues.
At most times, array just like a pointer.
Just remember you can't modify array!
And y++ is y = y + 1.
char y[] = "Hello";
So you do modify array when you y++!!
It will produce error: lvalue required as increment operand.
Since you've defined both x and y as arrays, you can't modify them. One possibility would be to use pointers instead:
char x[10];
char *xx = x;
char *y = "Hello";
while (*y != '\0')
*xx++ = *y++;
Note that I've also fixed your termination condition -- a pointer won't become NULL just because it's reached the end of a string.
We can not modify a array name, but What about argv++ in f(int argv[])?
Quotes from K&R in p99 “an array name is not a varible; construction like a = pa and a++ are illegal" which says the name of an array is a synonym for the location of the initial element.”
But why in function parameter func(char *argv[]), we can do argv++ despite of argv is a array name.
And in int *a[10], we can't do the a++ like argv++.
The name of array is a synonym for the location of the initial element. ---K&R
arrayname++ is illegal.
In function parameter, such as char *argv[], it is the same as char **argv. type *arrayname_para[] in parameter is a another synonym for type **arrayname_para.
Array is a static continuous block of allocated memory. Array names are immutable references to the first block memory. An attempt to increment the address (referenced by name of array) would result in loss (better to say deference) of other memory locations.
Say we have array
int p[]={10,20,30}
Here p (by design) refers to index 0. Say somewhere we increment p as :
p++
Assuming increment to be allowed would result in p to point to index 1. Now thinking what p[1]=? p[1] would then translate to dereferencing the value one place to the right of the current p location Or location p[2] for original array.
Do this repeatedly and soon tracking the array indices would become very troublesome.
So to avoid such mishaps array names(lvalues) addresses are immutable.
Another concept is word addressing and byte addressing:-
Character Arrays(string) in C are byte addressable instead of being word addressable. So if we have an array
int a[]={10,20,30}
printf("%d",*(a+1)) //Ouput:20 (int is word addressable)
printf("%d",*(++a)) // Error: Array references are immutable
int* cpya=a;
printf("%d",*(++cpya)) /* Output:20 (cpy is not array reference but a copy. Hence is Mutable) */
char b[]="Hello"
printf("%c",*(++b)) // Error : Array references are immutable
printf("%c",*(b+1)) /* undefined_behavior as character Array(strings) are byte addressable and not word addressable */
printf("%c",*(b+sizeof(char)*1)) // Output :e (It's byte addressable).
To understand more I suggest reading the official docs for B Programming Lang at
[B Reference Manual- Data Objects][1]
Arrays are constant pointers. We can't change them.
int q;
int *const p = &q;
p = NULL; // this is not allowed.

difference between char *(arr[5]) and char (*arr)[5]

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);

Why does char* create a string?

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 :)

Resources