Why is the operator (*) needed to access the value of an int* variable but not for char*?
char *char_ptr;
int *int_ptr;
int mem_size = 50;
char_ptr = (char *) malloc(mem_size);
strcpy(char_ptr, "This is memory is located on the heap.");
printf("char_ptr (%p) --> '%s'\n", char_ptr, char_ptr);
int_ptr = (int *) malloc(12);
*int_ptr = 31337;
printf("int_ptr (%p) --> %d\n", int_ptr, *int_ptr);
Output:
char_ptr (0x8742008) --> 'This is memory is located on the heap.'
int_ptr (0x8742040) --> 31337
This is because of the way the printf format specifiers work: the %s format expects, for its corresponding argument, a pointer to a character (more precisely, the address of a nul-terminated string - which can be an array of char, an allocated buffer with at least one zero byte in it, or a string literal), so you can just give it the char_ptr variable as-is; on the other hand, the %d format expects an integer (not a pointer-to-integer), so you have to dereference the int_ptr variable using the * operator.
Note on Good Programming Style: As mentioned in the comments to your question, be sure to call free() at some point on every buffer allocated with malloc, or you will introduce memory leaks into your code. Also see: Do I cast the result of malloc?.
You also can use the expression *char_ptr. It has the type char and the expression will yield the pointed character that is 'T' - the first character of the stored string literal.
This is the same as *int_ptr that returns the first element of the allocated integer array.
As for the conversion specifier %s then it expects an argument of the type char * that points to a string. On the other hand, the conversion specifier %d expects an object of the type int
You could use the conversion specifier %c. to output just a single character of the pointed string like
printf( "%c", *char_ptr );
For any pointer or array p and index i, the expression p[i] is exactly equal to *(p + i). From that follows that *p is equal to p[0].
In your case *int_ptr is equal to int_ptr[0].
If you did the same with char_ptr (i.e. *char_ptr) you would have char_ptr[0] which is a single character, that could be printed with %d as well:
printf("char_ptr (%p) --> '%d'\n", char_ptr, *char_ptr);
This would print the decimal representation of the first character in the string.
"Why is operator (*) needed to access the value of an int* variable and not for char* ?"
Because at the printf() function, the format specifier %s expects a matching argument of type char * - a pointer to a string, while %d expects an argument of type int.
In the latter case, the dereference operator * is required to dereference int_ptr and yield the value of the int object int_ptr points to.
As char_ptr is already of type char* as required by %s, there is no need to dereference it.
Side notes:
1.
int_ptr = (int *) malloc(12);
Note that with 12 Bytes on most modern system you be able to allocate only 1 int object as it requires 8 Byte. The remaining 4 Byte are not sufficient to hold another.
If you want to allocate space for only one int, use sizeof(*int_ptr):
int_ptr = (*int) malloc(sizeof(*int_ptr));
2.
Also don´t forget to free() the storage allocated by malloc() after its use:
free(int_ptr);
free(char_ptr);
3.
Furthermore there is no need to cast the return value of malloc(): Do I cast the result of malloc?
char_ptr = malloc(mem_size);
int_ptr = malloc(sizeof(*int_ptr));
Related
Some example code:
#include <stdio.h>
void func0(char *x)
{
printf("func0, %s, %zu\n", x, sizeof(x));
}
//for comparison with func0
void func1(char **x)
{
printf("func1, %s, %zu\n", *x, sizeof(*x));
}
int main()
{
char x[10] = "hello";
printf("%s, %zu, %zu, %zu\n", x, sizeof(x), sizeof(*x), sizeof("hello"));
func0(x);
func1(&x);
return 0;
}
For func1() (for comparison with func0), there is a "warning: incompatible pointer types passing 'char (*)[10]' to parameter of type 'char **'" and "Segmentation fault" error.
But for func0(), isn't the type 'char [10]' converted to 'char *'? If so, how is printf("%s") still able to print out "hello"? As shown in the output of func0():
hello, 10, 1, 6
func0, hello, 8
Is the information of length (i.e. N of char[N]) passed to func0?
What is the difference between x in func0 and *x in func1? Aren't they both an address pointing to a char?
Thank you very much.
[EDIT] Thank you so much for the detailed answers!
Let me summarise the warning and error for func1().
char x[10] = "hello";
The type of &x is char (*)[10], which is a pointer to an array, not pointer to pointer (e.g. char **). Hence the warning.
x is already the address (pointing to the string), and you can only take the address of an actual memory space. &x is not the address of x. **x in func1(): trying to read from an illegal address (the value of "H" in this example?), hence the Segmentation fault.
The extra question is:
What is the use case for using &x (e.g. char (*) [N])?
I see the difference between x and &x, char * / char[N] vs. char (*) [N], but I cannot figure out a case when you have to use char( *) [N]. x and &x are the same address after all.
there is a "warning: incompatible pointer types passing char (*)[10] to parameter of type char **" and "Segmentation fault" error.
That's right, &x expression produces a pointer to array of ten characters, hence the warning. If you want to pass a pointer to pointer, make a pointer, and take a pointer of it:
char *px = x; // alternatively you could write &x[0]
func1(&px);
But for func0(), isn't the type char [10] converted to char *?
That's right, character array "decays" to character pointer when you make a function call.
how is printf("%s") still able to print out "hello"
This is possible because x contains a null-terminated sequence of characters. Therefore, printf does not need to know the size of the array when processing %s: stopping at '\0' is sufficient.
Essentially, %s does not need to know the size of the array, it needs to know the length of the string, in the same way strlen "knows" it:
printf("func0, %s, %lu\n", x, strlen(x));
// Prints hello 5
I see the difference between x (char / char[N]) and &x, but I cannot figure out a case when you have to use char(*) [N]
Here is a small example:
void print_many(char (*rows)[10], size_t count) {
for (size_t i = 0 ; i != count ; i++) {
printf("%zu: %s\n", i+1, rows[i]);
}
}
you call it like this:
char rows[10][] = {"quick", "brown", "fox"};
print_many(rows, 3);
Demo.
Is the information of length (i.e. N of char[N]) passed to func0?
No. The parameter for func0 is char *. This is a pointer to char, nothing else. There is no length associated with it.
But for func0(), isn't the type 'char [10]' converted to 'char *'?
Yes. When x, which has type char [10], is used as a function argument, it is automatically converted to a pointer to its first argument. So the function receives a pointer to char.
If so, how is printf("%s") still able to print out "hello"?
The pointer passed to printf must point to the first character of a string whose end is marked by a null character. Thus, the pointer it receives points to a char containing 'h', after which there is a char containing 'e', then 'l', then 'l', then 'o', then zero. printf prints characters one by one until it sees the zero.
What is the difference between x in func0 and *x in func1?
If func1 were passed a pointer to a pointer to char, then using *x to pass a pointer to char to printf could be okay. However, your call to func1 is func1(&x). This is not passing a pointer to a pointer to a char. Since x is an array of 10 char, &x is a pointer to an array of 10 char. It is not a pointer to a pointer.
An array is not a pointer. Although arrays are often automatically converted to pointers, this automatic conversion does not happen when the array is the operand of unary &. (It also does not happen when the array is the operand of sizeof or _Alignof, or when the array is a string literal used to initialize an array.)
To produce a pointer to a pointer to char from the array x, you would have to take the address of a pointer to its first character. There is no way to do this in a simple expression, because x is the array, not a pointer. You could create a pointer to its first character with char *y = x;, and then you could pass &y to func1.
Note
Do not print sizes from sizeof using %lu. Use %zu. The z modifier is specifically for the size type, size_t.
For the question in the title, print("%s\n", x) does not care if x is a pointer or an array, as long as it contains a zero-terminated string.
Next, only the topmost dimension of an array can be transparently coerced to a pointer, that's what the warning about.
Finally, &x points to the zero elements of your array, so when you dereference it in func1, array's first few elements (might be even eight of them, so two the rightmost are not even initialized) are reinterpreted as a pointer-to char which almost certainly points to nowhere. That's how the segfault arised.
printf("%lu \n", sizeof(*"327"));
I always thought that size of a pointer was 8 bytes on a 64 bit system but this call keeps returning 1. Can someone provide an explanation?
Putting * before a string literal will dereference the literal (as string literal are array of characters and will decay to pointer to its first element in this context). The statement
printf("%zu \n", sizeof(*"327"));
is equivalent to
printf("%zu \n", sizeof("327"[0]));
"327"[0] will give the first element of the string literal "327", which is character '3'. Type of "327", after decay, is of char * and after dereferencing it will give a value of type char and ultimately sizeof(char) is 1.
The statement:
printf("%lu \n", sizeof(*"327"));
actually prints the size of a char, as using * dereferences the first character of string 327. Change it to:
char* str = "327";
printf("%zu \n", sizeof(str));
Note that we need to use %zu here, instead of %lu, because we are printing a size_t value.
The string literal is an anonymous, static array of chars, which decays to a pointer to its first character -- that is, a pointer value of type char *.
As a result expression like *"abc" is equivalent to *someArrayOfCharName, which in turn is equivalent to *&firstCharInArray which results in firstCharInArray. And sizeof(firstCharInArray) is sizeof(char) which is 1.
Good answer by haccks.
Also, the behaviour of your code is undefined, because you have used the wrong format specifier.
So, use %zu instead of %lu because sizeof() returns size_t and size_t is unsigned.
C11 Standard: §7.21.6.1: Paragraph 9:
If a conversion specification is invalid, the behavior is
undefined.225) If any argument is not the correct type for the
corresponding conversion specification, the behavior is undefined.
Hi please advise me on the following output:
main()
{
char ***x = "jjhljlhjlhjl";
char **q = *x;
printf("x:%s\n",x);
printf("q:%s\n",&q);
}
Output:
x:jjhljlhjlhjl
q:jjhl
Why is q doesn't print the whole of x ?
Your program invokes undefined behavior, so there are not really any limitations on what it may output.
char ***x = "jjhljlhjlhjl";
Although x is a pointer to a pointer to a pointer, it is assigned the address of a string literal.
char **q = *x;
q is a pointer to a pointer, and is assigned the result of dereferencing x. Since x is actually pointing to an object of incompatible type, the result of derferencing it is undefined.
If we pretend like this is supposed to work, then *x is now a pointer to a pointer, and so it might treat the sizeof(char **) bytes of the string literal as if it were an address and assign that value to q.
printf("x:%s\n",x);
Since x is a pointer, that pointer value is passed to printf(). Since the %s is provided, the pointer value is treated like a string. Since x was assigned the address of a string literal, that string is what gets printed.
printf("q:%s\n",&q);
The address of q is passed to printf(). Since the %s is provided, the pointer value is treated like a string. However, derferencing the contents of that pointer is actually sizeof(char **) bytes of the string literal. There is no guarantee that the bytes read will be properly NUL terminated, so it is just happenstance that something got printed at all.
The issue is the string "jjhljlhjlhjl" is only a char *, whereas you assign it to a char ***. When you print x, it gets interpreted as a char * by printf, which winds up being the correct string.
As for printing &q as a string address, you're effectively printing the contents of q. When you dereference x, you get a char **, which in your case, is 4 bytes. But because x actually points to text data, *x will grab the first four bytes (i.e. characters) of your string. The fact that it's printing only four characters is pure chance.
I am running this piece of code on a hardware.
unsigned char *buf;
buf = malloc(sizeof(int));
printf("Address of buf %d\n" , &buf);
if(!buf)
return MEMORYALLOC_FAILURE;
The malloc is returning negative value. What could be the problem?
Address returned by malloc is not negative or positive, it just address, use %p to print it, not %d:
printf("Address of buf %p\n" , &buf);
And if you want to print the address returned from malloc, remove the ampersand:
printf("Address of buf %p\n" , buf);
You're printing the address of a memory location as a signed integer. If the memory address--for example on a 32bit machine--is more than 2,147,483,647 (0x7FFFFFFF) it will display as a negative number.
In this case you're also printing the address of a local variable on the stack rather than the address returned by malloc.
The error with using %d to print a pointer-sized value is that pointers may vary in size. The correct approach therefore would be to use the printf specifier for pointers, %p:
// nb: we don't take the address of buf,
// buf is already a pointer (thus its *value* is an address)
printf("Address of buf %p\n", buf);
Type mismatch:
you try to print an address with the specifier for an int ("%d"). You should use "%p" and cast the value to void*
printf("Address of buf %p\n" , (void*)&buf);
Also note the above will not tell you where the allocated memory is. For that you'd need
printf("Address of newly allocated memory %p\n" , (void*)buf);
The cast to void* is mandated by the C99 standard (emphasis is mine)
The argument shall be a pointer to void. The value of the pointer is converted to a sequence of printing characters, in an implementation-defined manner.
Also note that pointers to void need not have the same representation as pointers to other types.
malloc returns either NULL (aka 0) or a memory address. Memory addresses cannot be negative. You just converted the pointer itself to a number, resulting in a negative number.
malloc returns a pointer. It never returns a negative value. If you think it is then you probably have a broken everything. On the other hand if you mean it returns a null pointer, then it means you are unable to allocate that memory.
I am thinking of something like:
#include <stdio.h>
#include <conio.h>
#include <stdlib.h>
int main(void) {
//test pointer to string
char s[50];
char *ptr=s;
printf("\nEnter string (s): ");
fgets(s, 50, stdin);
printf("S: %s\nPTR: %s\n", s, *ptr);
system("PAUSE");
return 0;
}
Or should I use a for loop with *(s+i) and the format specifier %c?
Is that the only possible way to print a string through a pointer and a simple printf?
Update: The printf operates with the adress of the first element of the array so when I use *ptr I actually operate with the first element and not it's adress. Thanks.
The "%s" format specifier for printf always expects a char* argument.
Given:
char s[] = "hello";
char *p = "world";
printf("%s, %s\n", s, p);
it looks like you're passing an array for the first %s and a pointer for the second, but in fact you're (correctly) passing pointers for both.
In C, any expression of array type is implicitly converted to a pointer to the array's first element unless it's in one of the following three contexts:
It's an argument to the unary "&" (address-of) operator
It's an argument to the unary "sizeof" operator
It's a string literal in an initializer used to initialize an array object.
(I think C++ has one or two other exceptions.)
The implementation of printf() sees the "%s", assumes that the corresponding argument is a pointer to char, and uses that pointer to traverse the string and print it.
Section 6 of the comp.lang.c FAQ has an excellent discussion of this.
printf("%s\n", ptr);
Is this what you want?
By the way, from printf(3), here's the documentation for the s conversion specifier (i.e %s):
If no l modifier is present: The const char * argument is expected to
be a pointer to an array of character type (pointer to a string).
Characters from the array are written up to (but not including) a
terminating null byte ('\0'); if a precision is specified, no more
than the number specified are written. If a precision is given, no
null byte need be present; if the precision is not specified, or is
greater than the size of the array, the array must contain a
terminating null byte.
you should do "printf("S: %s\nPTR: %s\n", s, ptr);
" instead of printf("S: %s\nPTR: %s\n", s, *ptr);
difference between ptr and *ptr is: ptr gives you the address in the memory of the variable you are pointing to and *ptr gives rather the value of the pointed variable In this case is *ptr = ptr[0]
this code will show what i mean:
printf("\tS: %s\n\tPTR: %s\n\tAddress of the pointed Value: %x\n\tValue of the whole String: %s\n\tValue of the first character of the String: %c\n", s, ptr,ptr,ptr,*ptr);
In my experience you should get segmentation fault when you try to use %s directive with *p.