Passing a string literal as a function parameter defined as a pointer - c

I am reading the chapter on arrays and pointers in Kernighan and Richie's The C Programming Language.
They give the example:
/* strlen:  return length of string s */
int strlen(char *s)
{
    int n;
    for (n = 0; *s != '\0'; s++)
        n++;
    return n;
}
And then say:
“Since s is a pointer, incrementing it is perfectly legal; s++ has no effect on the character string in the function that called strlen, but merely increments strlen’s private copy of the pointer. That means that calls like
strlen("hello, world");  /* string constant */
strlen(array);           /* char array[100]; */
strlen(ptr);             /* char *ptr; */
all work.”
I feel like I understand all of this except the first call example: Why, or how, is the string literal "hello, world" treated as a char *s? How is this a pointer? Does the function assign this string literal as the value of its local variable *s and then use s as the array name/pointer?

To understand how a string like "Hello World" is converted to a pointer, it is important to understand that, the string is actually hexadecimal data starting at an address and moving along till it finds a NULL
So that means, every string constant such as "Hello World" is stored in the memory somewhere
Possibility would be:
0x10203040 : 0x48 [H]
0x10203041 : 0x65 [e]
0x10203042 : 0x6C [l]
0x10203043 : 0x6C [l]
0x10203044 : 0x6F [o]
0x10203045 : 0x20 [' ']
0x10203046 : 0x57 [W]
0x10203047 : 0x6F [o]
0x10203048 : 0x72 [r]
0x10203049 : 0x6C [l]
0x1020304A : 0x64 [d]
0x1020304B : 0x00 [\0]
So, when this function is called with the above values in the memory, [left side is address followed by ':' and the right side is ascii value of the character]
int strlen(const char *s)
{
int n;
for (n = 0; *s != ′\0′; s++)
n++;
return n;
}
strlen("Hello World");
at that time, what gets passed to strlen is the value 0x10203040 which is the address of the first element of the character array.
Notice, the address is passed by value.. hence, strlen has its own copy of the address of "Hello World". starting from n = 0, following uptil I find \0 in the memory, I increment n and also the address in s(which then gets incremented to 0x10203041) and so on, until it finds \0 at the address 0x1020304B and returns the string length.

"hello, world"
is an array of char (type is char[13]). The value of an array of char in an expression is a pointer to char. The pointer points to the first element of the array (i.e., the value of "hello, world" is &"hello, world"[0]).

Note that:
A pointer is (basically) a value pointing to a memory address.
A static string like "hello, word" is stored somewhere in memory
So, a pointer could as easily simply point to a static string as to any other (dynamical) structure that is stored in memory (like an array of characters). There is really no difference with the other provided examples.

Does the function assign this string literal as the value of its local variable *s
and then use s as the array name/pointer?
Yes

As it says in the first paragraph of the same page (Page 99, K&R2):
"By definition, the value of a variable or expression of type array is
the address of element zero of the array."
The value of "hello, world" would be the address of 'h'.

char str[] = "Hello, world";
strlen(str);
string in C are array of characters with terminating NULL ('\0'), that mean it should be in the memory some where.
so what is the difference of sending a stored string as above and sending it directly as below
strlen("Hello, World");
The answer is both are same, but where the string is stored and how it's handled, here comes the compiler and stack.
The compiler at compile time pushes the string in to stack and send the starting address (char*) in the stack, the calling function sees a pointer and access the string.
The compiler also add codes after exist form the function to restore the stack in the correct place thus deleting the temporary string created
Note: the above is implementation dependent of the compiler, but most of the compiler works this way

Related

Why can I store a string in the memory address of a char?

I'm starting to understand pointers and how to dereference them etc. I've been practising with ints but I figured a char would behave similarly. Use the * to dereference, use the & to access the memory address.
But in my example below, the same syntax is used to set the address of a char and to save a string to the same variable. How does this work? I think I'm just generally confused and maybe I'm overthinking it.
int main()
{
char *myCharPointer;
char charMemoryHolder = 'G';
myCharPointer = &charMemoryHolder;
printf("%s\n", myCharPointer);
myCharPointer = "This is a string.";
printf("%s\n", myCharPointer);
return 0;
}
First, you need to understand how "strings" work in C.
"Strings" are stored as an array of characters in memory. Since there is no way of determining how long the string is, a NUL character, '\0', is appended after the string so that we know where it ends.
So for example if you have a string "foo", it may look like this in memory:
--------------------------------------------
| 'f' | 'o' | 'o' | '\0' | 'k' | 'b' | 'x' | ...
--------------------------------------------
The things after '\0' are just stuff that happens to be placed after the string, which may or may not be initialised.
When you assign a "string" to a variable of type char *, what happens is that the variable will point to the beginning of the string, so in the above example it will point to 'f'. (In other words, if you have a string str, then str == &str[0] is always true.) When you assign a string to a variable of type char *, you are actually assigning the address of the zeroth character of the string to the variable.
When you pass this variable to printf(), it starts at the pointed address, then goes through each char one by one until it sees '\0' and stops. For example if we have:
char *str = "foo";
and you pass it to printf(), it will do the following:
Dereference str (which gives 'f')
Dereference (str+1) (which gives 'o')
Dereference (str+2) (which gives another 'o')
Dereference (str+3) (which gives '\0' so the process stops).
This also leads to the conclusion that what you're currently doing is actually wrong. In your code you have:
char charMemoryHolder = 'G';
myCharPointer = &charMemoryHolder;
printf("%s\n", myCharPointer);
When printf() sees the %s specifier, it goes to address pointed to by myCharPointer, in this case it contains 'G'. It will then try to get next character after 'G', which is undefined behaviour. It might give you the correct result every now and then (if the next memory location happens to contain '\0'), but in general you should never do this.
Several comments
Static strings in c are treated as a (char *) to a null terminated
array of characters. Eg. "ab" would essentially be a char * to a block of memory with 97 98 0. (97 is 'a', 98 is 'b', and 0 is the null termination.)
Your code myCharPointer = &charMemoryHolder; followed by printf("%s\n", myCharPointer) is not safe. printf should be passed a null terminated string, and there's no guarantee that memory contain the value 0 immediately follows your character charMemoryHolder.
In C, string literals evaluate to pointers to read-only arrays of chars (except when used to initialize char arrays). This is a special case in the C language and does not generalize to other pointer types. A char * variable may hold the address of either a single char variable or the start address of an array of characters. In this case the array is a string of characters which has been stored in a static region of memory.
charMemoryHolder is a variable that has an address in memory.
"This is a string." is a string constant that is stored in memory and also has an address.
Both of these addresses can be stored in myCharPointer and dereferenced to access the first character.
In the case of printf("%s\n", myCharPointer), the pointer will be dereferenced and the character displayed, then the pointer is incremented. It repeasts this until finds a null (value zero) character and stops.
Hopefully you are now wondering what happens when you are pointing to the single 'G' character, which is not null-terminated like a string constant. The answer is "undefined behavior" and will most likely print random garbage until it finds a zero value in memory, but could print exactly the correct value, hence "undefined behavior". Use %c to print the single character.

Understanding two ways of declaring a C string [duplicate]

This question already has answers here:
How to declare strings in C [duplicate]
(4 answers)
Closed 8 years ago.
A few weeks ago I started learning the programming language C. I have knowledge in web technologies like HMTL/CSS, Javscript, PHP, and basic server administration, but C is confusing me. To my understanding, the C language does not have a data type for strings, just characters, however I may be wrong.
I have heard there are two ways of declaring a string. What is the difference between these two lines of declaring a string:
a.) char stringName[];
b.) char *stringName;
I get that char stringName[]; is an array of characters. However, the second line confuses me. To my understanding the second line makes a pointer variable. Aren't pointer variables supposed to be the memory address of another variable?
In the C language, a "string" is, as you say, an array of char. Most string functions built into the C spec expect the string to be "NUL terminated", meaning the last char of the string is a 0. Not the code representing the numeral zero, but the actual value of 0.
For example, if you're platform uses ASCII, then the following "string" is "ABC":
char myString[4] = {65, 66, 67, 0};
When you use the char varName[] = "foo" syntax, you're allocating the string on the stack (or if its in a global space, you're allocating it globally, but not dynamically.)
Memory management in C is more manual than in many other langauges you may have experience with. In particular, there is the concept of a "pointer".
char *myString = "ABC"; /* Points to a string somewhere in memory, the compiler puts somewhere. */
Now, a char * is "an address that points to a char or char array". Notice the "or" in that statement, it is important for you, the programmer, to know what the case is.
It's important to also ensure that any string operations you perform don't exceed the amount of memory you've allocated to a pointer.
char myString[5];
strcpy(myString, "12345"); /* copy "12345" into myString.
* On no! I've forgot space for my nul terminator and
* have overwritten some memory I don't own. */
"12345" is actually 6 characters long (don't forget the 0 at the end), but I've only reserved 5 characters. This is what's called a "buffer overflow", and is the cause of many serious bugs.
The other difference between "[]" and "*", is that one is creating an array (as you guessed). The other one is not reserving any space (other than the space to hold the pointer itself.) That means that until you point it somewhere that you know is valid, the value of the pointer should not be used, for either reading or writing.
Another point (made by someone in the comment)
You cannot pass an array as a parameter to a function in C. When you try, it gets converted to a pointer automatically. This is why we pass around pointers to strings rather than the strings themselves
In C, a string is a sequence of character values followed by a 0-valued byte1 . All the library functions that deal with strings use the 0 terminator to identify the end of the string. Strings are stored as arrays of char, but not all arrays of char contain strings.
For example, the string "hello" is represented as the character sequence {'h', 'e', 'l', 'l', 'o', 0}2 To store the string, you need a 6-element array of char - 5 characters plus the 0 terminator:
char greeting[6] = "hello";
or
char greeting[] = "hello";
In the second case, the size of the array is computed from the size of the string used to initialize it (counting the 0 terminator). In both cases, you're creating a 6-element array of char and copying the contents of the string literal to it. Unless the array is declared at file scope (oustide of any function) or with the static keyword, it only exists for the duration of the block in which is was declared.
The string literal "hello" is also stored in a 6-element array of char, but it's stored in such a way that it is allocated when the program is loaded into memory and held until the program terminates3, and is visible throughout the program. When you write
char *greeting = "hello";
you are assigning the address of the first element of the array that contains the string literal to the pointer variable greeting.
As always, a picture is worth a thousand words. Here's a simple little program:
#include <string.h>
#include <stdio.h>
#include <ctype.h>
int main( void )
{
char greeting[] = "hello"; // greeting contains a *copy* of the string "hello";
// size is taken from the length of the string plus the
// 0 terminator
char *greetingPtr = "hello"; // greetingPtr contains the *address* of the
// string literal "hello"
printf( "size of greeting array: %zu\n", sizeof greeting );
printf( "length of greeting string: %zu\n", strlen( greeting ) );
printf( "size of greetingPtr variable: %zu\n", sizeof greetingPtr );
printf( "address of string literal \"hello\": %p\n", (void * ) "hello" );
printf( "address of greeting array: %p\n", (void * ) greeting );
printf( "address of greetingPtr: %p\n", (void * ) &greetingPtr );
printf( "content of greetingPtr: %p\n", (void * ) greetingPtr );
printf( "greeting: %s\n", greeting );
printf( "greetingPtr: %s\n", greetingPtr );
return 0;
}
And here's the output:
size of greeting array: 6
length of greeting string: 5
size of greetingPtr variable: 8
address of string literal "hello": 0x4007f8
address of greeting array: 0x7fff59079cf0
address of greetingPtr: 0x7fff59079ce8
content of greetingPtr: 0x4007f8
greeting: hello
greetingPtr: hello
Note the difference between sizeof and strlen - strlen counts all the characters up to (but not including) the 0 terminator.
So here's what things look like in memory:
Item Address 0x00 0x01 0x02 0x03
---- ------- ---- ---- ---- ----
"hello" 0x4007f8 'h' 'e' 'l' 'l'
0x4007fc 'o' 0x00 ??? ???
...
greetingPtr 0x7fff59079ce8 0x00 0x00 0x00 0x00
0x7fff59879cec 0x00 0x40 0x7f 0xf8
greeting 0x7fff59079cf0 'h' 'e' 'l' 'l'
0x7fff59079cf4 'o' 0x00 ??? ???
The string literal "hello" is stored at a vary low address (on my system, this corresponds to the .rodata section of the executable, which is for static, constant data). The variables greeting and greetingPtr are stored at much higher addresses, corresponding to the stack on my system. As you can see, greetingPtr stores the address of the string literal "hello", while greeting stores a copy of the string contents.
Here's where things can get kind of confusing. Let's look at the following print statements:
printf( "greeting: %s\n", greeting );
printf( "greetingPtr: %s\n", greetingPtr );
greeting is a 6-element array of char, and greetingPtr is a pointer to char, yet we're passing them both to printf in exactly the same way, and the string is being printed out correctly; how can that work?
Unless it is the operand of the sizeof or unary & operators, or is a string literal used to initialize another array in a declaration, an expression of type "N-element array of T" will be converted ("decay") to an expression of type "pointer to T", and the value of the expression will be the address of the first element of the array.
In the printf call, the expression greeting has type "6-element array of char"; since it isn't the operand of the sizeof or unary & operators, it is converted ("decays") to an expression of type "pointer to char" (char *), and the address of the first element is actually passed to printf. IOW, it behaves exactly like the greetingPtr expression in the next printf call4.
The %s conversion specifer tells printf that its corresponding argument has type char *, and that it it should print out the character values starting from that address until it sees the 0 terminator.
Hope that helps a bit.
1. Often referred to as the NUL terminator; this should not be confused with the NULL pointer constant, which is also 0-valued but used in a different context.
2. You'll also see the terminating 0-valued byte written as '\0'. The leading backslash "escapes" the value, so instead of being treated as the character '0' (ASCII 48), it's treated as the value 0 (ASCII 0)).
3. In practice, space is set aside for it in the generated binary file, often in a section marked read-only; attempting to modify the contents of a string literal invokes undefined behavior.
4. This is also why the declaration of greeting copies the string contents to the array, while the declaration of greetingPtr copies the address of the first element of the string. The string literal "hello" is also an array expression. In the first declaration, since it's being used to initialize another array in a declaration, the contents of the array are copied. In the second declaration, the target is a pointer, not an array, so the expression is converted from an array type to a pointer type, and the resulting pointer value is copied to the variable.
In C (and in C++), arrays and pointers are represented similarly; an array is represented by the address of the first element in the array (which is sufficient to gain access to the other elements, since elements are contiguous in memory within an array). This also means that an array does not, by itself, indicate where it ends, and thus you need some way of identifying the end of the array, either by passing around the length as a separate variable or by using some convention (such as that there is a sentinel value that is placed in the last position of the array to indicate the end of the array). For strings, the latter is the common convention, with '\0' (the NUL character) indicating the end of the string.

Where is a pointer variable's address stored when referencing a character variable?

Let's say we have a character pointer like this:
static char *example[]={"doctor","who","hello"};
I'm slightly confused at what is happening in this instance.
Does the pointer example simply have its own address?
Do the strings I have within the array each have a memory address different to *example
and each other?
Does the pointer example just simply reference each address and also initialize what's in
each address as shown by the declaration of the strings?
I'm only being using C for a few months, so I'm just trying to grasp the nuts and bolts of things, and I hear pointers are single-handedly the most important aspect of C.
Does the variable example simply have it's own address?
Yes, the variable has its own address.
Do the strings I have within the array each have a memory address different to *example
and each other?
Yes, each string has its own address, different from each other's. It's also different from the address of the variable example. The expression *example, however, is not the same as the variable example. See the next.
Does the pointer example just simply reference each address and also initialize what's in each address as shown by the declaration of the strings?
The variable example references the array of strings in the sense that the value of example (not its address) is the address of the array.
static char* example[] declares example as an array of pointers to char. The array is initialized to three string literals, so example[0] is "doctor", example[1] is "who", and example[2] is "hello".
Since example is an array, the array identifier example is going to evaluate to the address of the array's first element. If you try something like this:
printf ("%p %p %p\n", example, &example, &example[0]);
you'll see that they all have the same value. All these, however, are semantically different types.
example has the type array of pointers to char
&example has the type pointer to array of pointers to char
&example[0] has the type pointer to pointer to char.
Each element of the array has its own address. Try this:
printf ("%p %p %p\n", &example[0], &example[1], &example[2]);
The first will be the same address as the array, but the others will be offset from that address by the size of a pointer on your system (typically four bytes for a 32-bit system, 8 bytes for a 64-bit system).
The char that each pointer in your array example is pointing to is the first char of a string literal. Each string literal has its own address, probably in a read-only memory segment. You can try this too:
printf ("%p %p\n", &example[0], example[0]);
&example[0] is the address of the first pointer in the array of pointers to char.
example[0] is the first pointer in the array of pointers. Think of an array of int. Each element of that array would have an address and a value, the latter being an int. Since example is an array of pointers, each element of example is going to have an address and a value, the latter being a pointer.
You can repeat the exercise for &example[1], etc:
printf ("%p %p\n", &example[1], example[1]);
printf ("%p %p\n", &example[2], example[2]);
To sum up:
The array of pointers to char has the same address as its first element.
Each subsequent element, i.e., each subsequent pointer in the array, has its own address.
Each of those pointers points to (the first char of) a string, which has its own address.
Hope that's clear.
If you declare
char *example[] = {"doctor","who","hello"};
You get an array, of size 3, each of which holds one char* pointer. It is the same as
char *example[3] = {"doctor","who","hello"};
But, we really need to see how example is declared in your code to answer.
A picture might help. The following is not meant to represent any particular architecture - all address values are pulled out of thin air.
Item Address 0x00 0x01 0x02 0x03
---- ------- ---- ---- ---- ----
0x00004000 'd' 'o' 'c' 't'
0x00004004 'o' 'r' 0x00 'w'
0x00004008 'h' 'o' 0x00 'h'
0x0000400c 'e' 'l' 'l' 'o'
0x00004010 0x00 ?? ?? ??
... ... ...
example: 0x80001000 0x00 0x00 0x40 0x00
0x80001004 0x00 0x00 0x40 0x07
0x80001008 0x00 0x00 0x40 0x0b
The string literals "doctor", "who", and "hello" are all stored in such a way that they are allocated over the lifetime of the program (they have static storage duration), and they may be stored in a read-only data segment1.
The string literal "doctor" is stored at address 0x00004000, "who" is stored at address 0x00004007, and "hello" is stored at address 0x0000400b.
The array example also has static storage duration by virtue of the static keyword, but in practice will probably be stored in a different memory area than the string literals. The array starts at address 0x80001000, and each element occupies four bytes, so &example[0] == 0x80001000, &example[1] == 0x80001004, and &example[2] == 0x80001008.
Note that there's no separate storage location for a variable named example that points to the first element of the array. In C, the address of the first element is the same as the address of the array itself. This is important, and is one of the most consistently misunderstood aspects of the C language. Arrays are not pointers; rather, an array expression will be converted ("decay") to a pointer expression in most circumstances2, and the value of the expression will be the address of the first element. If you're really interested, the reasoning for this behavior is outlined in this paper by Dennis Ritchie; scroll down to the "Embryonic C" section for the explanation.
The value stored in example[0] is the address of the string literal "doctor". Similarly, example[1] stores the address of the string literal "who", and example[3] stores the address of the string literal "hello".
1. Because of this, the behavior on trying to modify the contents of a string literal is undefined - it may work as expected, it may crash, or it may fail to compile altogether. The compiler is not required to handle the situation in any particular way, so the behavior will vary between different compilers. You should never attempt to modify the contents of a string literal.
2. The exceptions to this rule are when the array expression is an operand of the sizeof or unary & operators, or is a string literal being used to initialize another array in a declaration.

I am pretty curious about char pointers

I have learned that char *p means "a pointer to char type"
and also I think I've also learned that char means to read
that amount of memory once that pointer reaches its' destination.
so conclusively, in
char *p = "hello World";
the p contains the strings' address and
the p is pointing right at it
Qusetions.
if the p points to the string, shouldn't it be reading only the 'h'???
since it only reads the sizeof a char?
why does `printf("%s", p) print the whole string???
I also learned in Rithcie's book that pointer variables don't possess a data type.
is that true???
So your string "hello world" occupies some memory.
[h][e][l][l][o][ ][w][o][r][l][d][\0]
[0][1][2][3][4][5][6][7][8][9][A][B ]
The pointer p does, in fact, only point to the first byte. In this case, byte 0. But if you use it in the context of
printf("%s", p)
Then printf knows to print until it gets the null character \0, which is why it will print the entire string and not just 'h'.
As for the second question, pointers do posses a data type. If you were to say it outloud, the name would probably be something like type "pointer to a character" in the case of p, or "pointer to an integer" for int *i.
Pointer variables don't hold a data type, they hold an address. But you use a data type so you know how many bytes you'll advance on each step, when reading from memory using that pointer.
When you call printf, the %s in the expression is telling the function to start reading at the address indicated by *p (which does hold the byte value for 'h', as you said), and stop reading when it reaches a terminating character. That's a character that has no visual representation (you refer to it as \0 in code). It tells the program where a string ends.
Here *p is a pointer to some location in memory, that it assumes to be 1 byte (or char). So it points to the 'h' letter. So p[0] or *(p+0) will give you p. But, your string ends with invisible \0 character, so when you use printf function it outputs all symbols, starting from the one, where *p points to and till `\0'.
And pointer is just a variable, that is able to hold some address (4, 8 or more bytes).
For question:
I also learned in Rithcie's book that pointer variables don't possess a data type. is that true???
Simply put, YES.
Data types in C are used to define a variable before its use. The definition of a variable will assign storage for the variable and define the type of data that will be held in the location.
C has the following basic built-in datatypes.int,float,double,char.
Quoting from C Data types
Pointer is derived data type, each data type can have a pointer associated with. Pointers don't have a keyword, but are marked by a preceding * in the variable and function declaration/definition. Most compilers supplies the predefined constant NULL, which is equivalent to 0.
if the p points to the string, shouldn't it be reading only the 'h'???
since it only reads the sizeof a char? why does printf("%s", *p) print
the whole string???
change your printf("%s", *p) to printf("%c", *p) you see what you want. both calls the printf in different ways on the basis of format specifier i.e string(%s) or char(%c).
to print the string use printf("%s", p);
to print the char use printf("%c", *p);
Second Ans. : Pointers possesses a data type. that's why you used char *p .

Arguments passed to puts function in C

I have only recently started learning C. I was going through the concept of arrays and pointers, when I came across a stumbling block in my understanding of it.
Consider this code -
#include<stdio.h>
int main()
{
char string[]="Hello";
char *ptr;
ptr=string;
puts(*ptr);
return(0);
}
It compiles, but runs into segmentation fault on execution.
The warning that I get is:
type error in argument 1 to `puts'; found 'char' expected 'pointer to char'
Now *ptr does return a character "H" and my initial impression was that it would just accept a char as an input.
Later, I came to understand that puts() expects a pointer to a character array as it's input, but my question is when I pass something like this - puts("H"), isn't that the same thing as puts(*ptr), given that *ptr does contain the character "H".
"H" is a string literal that consists of 2 bytes 'H' and '\0'. Whenever you have "H" in your code, a pointer to the memory region with 2 bytes is meant. *ptr simply returns a single char variable.
By doing puts(*str), you're dereferencing the str variable. This would then try and use the 'H' character as a memory address (since that's what str) points to, then segfault since it will be an invalid pointer (since it will probably fall outside your process' memory). This is because the puts function accepts a pointer as an argument.
What you really want is puts(str).
As an aside, the latter example puts("h") populates the string table with "h" at compile time and replaces the definition there with an implicit pointer.
The puts() function takes a pointer to a string and what you are doing is specifying a single character.
Take a look at this Lesson 9: C Strings.
So rather than doing
#include<stdio.h>
int main()
{
char string[]="Hello";
char *ptr;
ptr=string; // store address of first character of the char array into char pointer variable ptr
// ptr=string is same as ptr=&string[0] since string is an array and an
// array variable name is treated like a constant pointer to the first
// element of the array in C.
puts(*ptr); // get character pointed to by pointer ptr and pass to function puts
// *ptr is the same as ptr[0] or string[0] since ptr = &string[0].
return(0);
}
You should instead be doing
#include<stdio.h>
int main()
{
char string[]="Hello";
char *ptr;
ptr=string; // store address of first character of the char array into char pointer variable ptr
puts(ptr); // pass pointer to the string rather than first character of string.
return(0);
}
When ever you enter string in gets or want to display it using puts you had to actually pass the location of the pointer or the string
for example
char name[] = "Something";
if you want to print that
you have to write printf("%s",name); --> name actually stores the address of the string "something"
and by using puts if you want to display
puts(name) ----> same as here address is put in the arguments
No.
'H' is the character literal.
"H" is, in effect, a character array with two elements, those being 'H' and the terminating '\0' null byte.
puts is waiting as input a string pointer so it's waiting a memory address. but in your example you provided the content of the memory which is *ptr. the *ptr is the content of the memory with address ptr which is h
ptr is memory address
*ptr is the content of this memory
the input parameter of puts is an address type but you have provided a char type (content of the address)
the puts start the printing character by character starting by the address you give it as input until the memory which contain 0 and then it stop printing

Resources