I'm trying to store the memory location of the evil variable in the ptr variable, but instead of the memory location, the variable prints out the value within the variable and not it's location. Both the ptr variable and the &evil syntax print the same result which is the value of the variable and not it's location in memory. Could someone please nudge me in the right direction, and help me determine the syntax needed to store the memory location of a string/char variable in C?
int main()
{
char *ptr;
char evil[4];
memset(evil, 0x43, 4);//fill evil variable with 4 C's
ptr = &evil[0];//set ptr variable equal to evil variable's memory address
printf(ptr);//prints 4 C's
printf(&evil);//prints 4 C's
return 0;
}
That's normal, because the first parameter to printf is a format specifier, which is basically a char* pointing to a string. Your string will be printed as-is because it does not contain any format specifiers.
If you want to display a pointer's value as an address, use %p as a format specifier, and your pointer as subsequent parameter:
printf("%p", ptr);
However, note that your code invokes Undefined Behavior (UB) because your string is not null-terminated. Chances are it was null-terminated "out-of-luck".
Also notice that to be "correct code", cast the pointer to void* when sending it to printf, because different types of pointers may differ on certain platforms, and the C standard requires the parameter to be pointer-to-void. See this thread for more details: printf("%p") and casting to (void *)
printf("%p", (void*)ptr); // <-- C standard requires this cast, although it migh work without it on most compilers and platforms.
You need #include <stdio.h> for printf, and #include <string.h> for memset.
int main()
You can get away with this, but int main(void) is better.
{
char *ptr;
char evil[4];
memset(evil, 0x43, 4);//fill evil variable with 4 C's
This would be more legible if you replaced 0x43 by 'C'. They both mean the same thing (assuming an ASCII-based character set). Even better, don't repeat the size:
memset(evil, 'C', sizeof evil);
ptr = &evil[0];//set ptr variable equal to evil variable's memory address
This sets ptr to the address of the initial (0th) element of the array object evil. This is not the same as the address of the array object itself. They're both the same location in memory, but &evil[0] and &evil are of different types.
You could also write this as:
ptr = evil;
You can't assign arrays, but an array expression is, in most contexts, implicitly converted to a pointer to the array's initial element.
The relationship between arrays and pointers in C can be confusing.
Rule 1: Arrays are not pointers.
Rule 2: Read section 6 of the comp.lang.c FAQ.
printf(ptr);//prints 4 C's
The first argument to printf should (almost) always be a string literal, the format string. If you give it the name of a char array variable, and it happens to contain % characters, Bad Things Can Happen. If you're just printing a string, you can use "%s" as the format string:
printf("%s\n", ptr);
(Note that I've added a newline so the output is displayed properly.)
Except that ptr doesn't point to a string. A string, by definition, is terminated by a null ('\0') character. Your evil array isn't. (It's possible that there just happens to be a null byte just after the array in memory. Do not depend on that.)
You can use a field width to determine how many characters to print:
printf("%.4s\n", ptr);
Or, to avoid the error-prone practice of having to write the same number multiple times:
printf("%.*s\n", (int)sizeof evil, evil);
Find a good document for printf if you want to understand that.
(Or, depending on what you're doing, maybe you should arrange for evil to be null-terminated in the first place.)
printf(&evil);//prints 4 C's
Ah, now we have some serious undefined behavior. The first argument to printf is a pointer to a format string; it's of type const char*. &evil is of type char (*)[4], a pointer to an array of 4 char elements. Your compiler should have warned you about that (the format string has a known type; the following arguments do not, so getting their types correct is up to you). If it seems to work, it's because &evil points to the same memory location as &evil[0], and different pointer types probably have the same representation on your systems, and perhaps there happens to be a stray '\0' just after the array -- perhaps preceded by some non-printable characters that you're not seeing.
If you want to print the address of your array object, use the %p format. It requires an argument of the pointer type void*, so you'll need to cast it:
printf("%p\n", (void*)&evil);
return 0;
}
Putting this all together and adding some bells and whistles:
#include <stdio.h>
#include <string.h>
int main(void)
{
char *ptr;
char evil[4];
memset(evil, 'C', sizeof evil);
ptr = &evil[0];
printf("ptr points to the character sequence \"%.*s\"\n",
(int)sizeof evil, evil);
printf("The address of evil[0] is %p\n", (void*)ptr);
printf("The address of evil is also %p\n", (void*)&evil);
return 0;
}
The output on my system is:
ptr points to the character sequence "CCCC"
The address of evil[0] is 0x7ffc060dc650
The address of evil is also 0x7ffc060dc650
Using
printf(ptr);//prints 4 C's
causes undefined behavior since the first argument to printf needs to be a null terminated string. In your case it is not.
Could someone please nudge me in the right direction
To print an address, you need to use the %p format specifier in the call to printf.
printf("%p\n", ptr);
or
printf("%p\n", &evil);
or
printf("%p\n", &evil[0]);
See printf documentation for all the ways it can be used.
if you want to see the address of a char - without all the array / pointer / decay oddness
int main()
{
char *ptr;
char evil;
evil = 4;
ptr = &evil;
printf("%p\n",(void*)ptr);
printf("%p\n",(void*)&evil);
return 0;
}
Related
#include<stdio.h>
int main()
{
char str[7];
scanf("%s",&str);
for(i=0; i<7; i++)
{
printf("%x(%d) : %c\n",&str[i], &str[i], str[i]);
}
printf("\n\n%x(%d) : %c or %s",&str, &str, str, str);
return 0;
}
I'm confused about pointer of C Array because of Array with String.
Actually I want to save each character for single line input.
It is worked but I found something strange...
The main issue is &str and &str[0] have same address value.
But str have String Value with %s..
str[0] have Char Value with %c..
I used str with %c then it has first two numbers of str's address.
What is going on in Array..?
Where is real address for Stirng value??
And how can scanf("%s",&str) distribute String to each char array space?
Input : 123456789
62fe40(6487616) : 1
62fe41(6487617) : 2
62fe42(6487618) : 3
62fe43(6487619) : 4
62fe44(6487620) : 5
62fe45(6487621) : 6
62fe46(6487622) : 7
62fe40(6487616) : # 123456789
This is result window of my code.
You are confused because the string and the array are the same thing. - In the memory there are only data (and pointers to that data)
When you allocate an integer or a buffer for a string you reserve some of this memory. Strings in c is defined as a sequence of bytes terminated by one byte with the value 0 - The length is not known. With the fix length array you have a known size to work with.
The real value to the string is the pointer to the first character.
When you print with %c it expects a char - str[0] not the pointer - When you print with %s it expects a pointer to a sequence of chars.
printf("\n\n%x(%d) : %c or %s",&str, &str, str[0], str);
What is different between array String and common array in C?
An array is a contiguous sequence of objects of one type.1
A string is a contiguous sequence of characters terminated by the first null character.2 So a string is simply an array of characters where we mark the end by putting a character with value zero. (Often, strings are temporarily held in larger arrays that have more elements after the null character.)
So every string is an array. A string is simply an array with two extra properties: Its elements are characters, and a zero marks the end.
&str and &str[0] have same address value.
&str is the address of the array. &str[0] is the address of the first element.
These are the same place in memory, because the first element starts in the same place the array does. So, when you print them or examine them, they will often appear the same. (Addresses can have different representations, the same way you might write “200” or “two hundred” or “2•102” for the same number. So the same address might sometimes look different. In most modern systems, an address is just a simple number for a place in memory, and you will not see differences. But it can happen.)
printf("%x(%d) : %c\n",&str[i], &str[i], str[i]);
This is not a correct way to print addresses. To print an address properly, convert it to void * and use %p3:
printf("%p(%p) : %c\n", (void *) &str[i], (void *) &str[i], str[i]);
printf("\n\n%x(%d) : %c or %s",&str, &str, str, str);
…
I used str with %c then it has first two numbers of str's address.
In the above printf, the third conversion specification is %c, and the corresponding argument is str. %c is intended to be used for a character,4 but you are passing it an argument that is a pointer. What may have happened here is that printf used the pointer you passed it as if it were an int. Then printf may have used a part of that int as if it were a character and printed that. So you saw part of the address shown as a character. However, it is a bit unclear when you write “it has the first two numbers of str's address”. You could show the exact output to clarify that.
Although printf may have used the pointer as if it were an int, the behavior for this is not defined by the C standard. Passing the wrong type for a printf conversion is improper, and other results can occur, including the program printing garbage or crashing.
And how can scanf("%s",&str) distribute String to each char array space?
The proper way to pass str to scanf for %s is to pass the address of the first character, &str[0]. C has a special rule for arrays like str: If an array is used in an expression other than as the operand of sizeof or the address-of operator &, it is converted to a pointer to its first element.5 So, you can use scanf("%s", str), and it will be the same as scanf("%s", &str[0]).
However, when you use scanf("%s",&str), you are passing the address of the array instead of the address of the first character. Although these are the same location, they are different types. Recall that two different types of pointers to the same address might have different representations. Because scanf does not have knowledge of the actual argument type you pass it, it must rely on the conversion specifier. %s tells scanf to expect a pointer to a character.6 Passing it a pointer to an array is improper.
C has this rule because some machines have different types of pointers, and some systems might pass different types of pointers in different ways. Nonetheless, often code that passes &str instead of str behaves as the author desired because the C implementation uses the same representation for both pointers. So scanf may actually receive the pointer value that it needs to make %s work.7
Footnotes
1 C 2018 6.2.5 20. (This means the information comes from the 2018 version of the C standard, ISO/IEC 9899, Information technology—Programming Languages—C, clause 6.2.5, paragraph 20.)
2 C 2018 7.1.1 1. Note that the terminating null character is considered to be a part of the string, although it is not counted by the strlen function.
3 C 2018 7.21.6.1 8.
4 Technically, the argument should have type int, and printf converts it to unsigned char and prints the character with that code. C 2018 7.21.6.1 8.
5 C 2018 6.3.2.1 3. A string literal used to initialize an array, as in char x[] = "Hello";, is also not converted to a pointer.
6 C 2018 7.21.6.2 12.
7 Even if a C implementation uses the same representations for different types of pointers, that does not guarantee that using one pointer type where another is required will work. When a compiler optimizes a program, it relies on the program’s author having obeyed the rules, and the optimizations may change the program in ways that would not break a program that followed the rules but that do break a program that breaks the rules.
String is only some kind of the shorthand of the zero terminated char array. So there is no difference between the string and the "normal" array.
Where is real address for Stirng value??
Arrays are not pointers and they only decay to pointers. So there is no physical space in the memory where the address of the first element of the array is stored.
The main issue is &str and &str[0] have same address value.
It is not the issue - array is the chunk of memory. So the address of this chunk is the same as the address of its first element. The types are different.
I'm expecting a compile error , taking into account that a pointer has to be assigned in %p, but the codes below doesn't give me error when i intentionally assign a pointer to %s. By adding an ampersand &, by right it should generate the address of the array and assign the memory address into %p, instead of giving the value of the string. Unless I dereference the pointer, but I don't dereference the pointer at all, I never put an asterisk * in front of my_pointer in printf.
#include <stdio.h>
int main()
{
char words[] = "Daddy\0Mommy\0Me\0";
char *my_pointer;
my_pointer = &words[0];
printf("%s \n", my_pointer);
return 0;
}
please look at this :
printf("%s \n", my_pointer);
My understanding is , *my_pointer (with asterisk *)should give me the value of the string.
But my_pointer (without asterisk) shouldn't give me the value of the string, but it should give me only the memory address,but when I run this code, I get the value of string eventhough I didn't put the asterisk * at the front. I hope I'm making myself clear this time.
Here:
printf("%s \n", my_pointer);
%s, expects a char* and since my_pointer is a char* which points to an array holding a NUL-terminated string, the printf has no problems and is perfectly valid. Relevant quote from the C11 standard (emphasis mine):
7.21.6.1 The fprintf function
[...]
The conversion specifiers and their meanings are:
[...]
s - If no l length modifier is present, the argument shall be a pointer to the initial
element of an array of character type. 280) Characters from the array are
written up to (but not including) the terminating null character. If the
precision is specified, no more than that many bytes are written. If the
precision is not specified or is greater than the size of the array, the array shall
contain a null character.
[...]
IMO, You are being confused here:
taking into account that a pointer has to be assigned in %p, but the codes below doesn't give me error when i intentionally assign a pointer to %s
First of all, %s, %p etc are conversion specifiers. They are used in some functions like printf, scanf etc.
Next, you are the one specifying the type of the pointers. So here:
my_pointer = &words[0];
&words[0] as well as my_pointer is of type char*. Assigning these two is therefore perfectly valid as both are of the same type.
The compiler is treating your code exactly as it is required to.
The %s format specifier tells printf() to expect a const char * as the corresponding argument. It then deems that pointer to be the address of the first element of an array of char and prints every char it finds until it encounters one with value zero ('\0').
Strictly speaking, the compiler is not even required to check that my_pointer is, or can be implicitly converted to, a const char *. However, most modern compilers (assuming the format string is supplied at compile time) do that.
In c, array name is also pointer to the first element, means in your case words and &words[0] when as a pointer, they have the same value.
And, you assign it to another pointer of the same type, so this is legal.
About string in c, it's just an array of chars ending with '\0', with its name pointer to the first char.
Can somebody clealry explain me the concept behind multiple reference and dereference ? why does the following program gives output as 'h' ?
int main()
{
char *ptr = "hello";
printf("%c\n", *&*&*ptr);
getchar();
return 0;
}
and not this , instead it produces 'd' ?
int main()
{
char *ptr = "hello";
printf("%c\n", *&*&ptr);
getchar();
return 0;
}
I read that consecutive use of '*' and '&' cancels each other but this explanation does not provide the reason behind two different outputs generated in above codes?
The first program produces h because &s and *s "cancel" each other: "dereferencing an address of X" gives back the X:
ptr - a pointer to the initial character of "hello" literal
*ptr - dereference of a pointer to the initial character, i.e. the initial character
&*ptr the address of the dereference of a pointer to the initial character, i.e. a pointer to the initial character, i.e. ptr itself
And so on. As you can see, a pair *& brings you back to where you have started, so you can eliminate all such pairs from your dereference / take address expressions. Therefore, your first program's printf is equivalent to
printf("%c\n", *ptr);
The second program has undefined behavior, because a pointer is being passed to printf with the format specifier of %c. If you pass the same expression to %s, the word hello would be printed:
printf("%s\n", *&*&ptr);
Lets go through the important parts of the program:
char *ptr = "hello";
makes a pointer to char which points to the string literal "hello". Now, for the confusing part:
printf("%c\n", *&*&*ptr);
Here, %c expects a char. Let us look into what type *&*&*ptr is. ptr is a char*. Applying the dereference operator(*) gives a char. Applying the address-of operator to this char gives back the char*. This is repeated again, and finally, the * at the end gives us a char, the first character of the string literal "hello", which gets printed.
In the second program, in *&*&ptr, you first apply the & operator, which gives a char**. Applying * on this gives back the char*. This is repeated again and finally , we get a char*. But %c expects a char, not a char*. So, the second program exhibits Undefined Behavior as per the C11 standard (emphasis mine):
7.21.6.1 The fprintf function
[...]
If a conversion specification is invalid, the behavior is undefined.282 If any argument is not the correct type for the corresponding conversion specification, the behavior is undefined.
So, basically, anything can happen when you execute the second program. Your program might crash, emit a segmentation-fault, output weird things, or do something else.
BTW, you are right about saying:
I read that consecutive use of '*' and '&' cancels each other
Let's break down what *&*&*ptr actually is, but first, remember that when applying * to a pointer, it gives you what that pointer points to. On the other hand, when applying & to a variable, it gives you the address in memory for that variable.
Now, after getting a steady ground, let's see what you have here:
ptr is a pointer to a char, thus when doing *ptr it gives you the data which ptr points to, in this case, ptr points to a string "hello", however, a char can hold only one char, not a whole string, right? so, it point to the beginning of such a string, which is the first character in it, aka h.
Moving on...*&*&*ptr=*&*&(*ptr) = *&*&('h')= *&*(&'h') = *&*(ptr)=*&(*ptr) = *&('h')= *ptr = 'h'
If you apply the same pattern on the next function, I'm pretty sure you can figure it out.
SUMMARY: read pointers from the right to the left!
Somebody wrote the following C program and asked why gcc allows "to change the base address of an array". He was aware that the code is terrible but still wanted to know. I found the question interesting enough, because the relationship between arrays and pointers in C is subtle (behold the use of the address operator on the array! "Why would anybody do that?"), confusing and consequently often misunderstood. The question was deleted but I thought I ask it again, with proper context and -- as I hope -- a proper answer to go with it. Here is the original prog.
static char* abc = "kj";
void fn(char**s)
{
*s = abc;
}
int main()
{
char str[256];
fn(&str);
}
It compiles with gcc (with warnings), links and runs. What happens here? Can we change the base address of an array by taking its address, casting it to pointer to pointer (after all arrays are almost pointers in C, aren't they) and assigning to it?
It cannot work (even theoretically), because arrays are not pointers:
int arr[10]:
Amount of memory used is sizeof(int)*10 bytes
The values of arr and &arr are necessarily identical
arr points to a valid memory address, but cannot be set to point to another memory address
int* ptr = malloc(sizeof(int)*10):
Amount of memory used is sizeof(int*) + sizeof(int)*10 bytes
The values of ptr and &ptr are not necessarily identical (in fact, they are mostly different)
ptr can be set to point to both valid and invalid memory addresses, as many times as you will
The program doesn't change the "base address" of the array. It's not even trying to.
What you pass to fn is the address of a chunk of 256 characters in memory. It is numerically identical to the pointer which str would decay to in other expressions, only differently typed. Here, the array really stays an array -- applying the address operator to an array is one of the instances where an array does not decay to a pointer. Incrementing &str, for example, would increase it numerically by 256. This is important for multi dimensional arrays which, as we know, actually are one-dimensional arrays of arrays in C. Incrementing the first index of a "2-dimensional" array must advance the address to the start of the next "chunk" or "row".
Now the catch. As far as fn is concerned, the address you pass points to a location which contains another address. That is not true; it points to a sequence of characters. Printing that byte sequence interpreted as a pointer reveals the 'A' byte values, 65 or 0x41.
fn, however, thinking that the memory pointed to contains an address, overwrites it with the address where "kj" is residing in memory. Since there is enough memory allocated in str to hold an address, the assignment succeeds and results in a usable address at that location.
It should be noted that this is, of course, not guaranteed to work. The most common cause for failure should be alignment issues -- str is, I think, not required to be aligned properly for a pointer value. The standard mandates that arguments to functions must be assignment-compatible with the parameter declarations. Arbitrary pointer types cannot be assigned to each other (one needs to go through void pointers for that, or cast).
Edit: david.pfx pointed out that (even with a proper cast) the code invokes undefined behaviour. The standard requires access to objects through compatible lvalues (including referenced pointers) in section 6.5/7 of the latest public draft. When casting properly and compiling with gcc -fstrict-aliasing -Wstrict-aliasing=2 ... gcc warns about the "type punning". The rationale is that the compiler should be free to assume that incompatible pointers do not modify the same memory region; here it is not required to assume that fn changes the contents of str. This enables the compiler to optimize away reloads (e.g. from memory to register) which would otherwise be necessary. This will play a role with optimization; a likely example where a debugging session would fail to reproduce the error (namely if the program being debugged would be compiled without optimization for debugging purposes). That being said, I'd be surprised if a non-optimizing compiler would produce unexpected results here, so I let the rest of the answer stand as is.--
I have inserted a number of debug printfs to illustrate what's going on. A live example can be seen here: http://ideone.com/aL407L.
#include<stdio.h>
#include<string.h>
static char* abc = "kj";
// Helper function to print the first bytes a char pointer points to
void printBytes(const char *const caption, const char *const ptr)
{
int i=0;
printf("%s: {", caption);
for( i=0; i<sizeof(char *)-1; ++i)
{
printf("0x%x,", ptr[i]);
}
printf( "0x%x ...}\n", ptr[sizeof(char *)-1] );
}
// What exactly does this function do?
void fn(char**s) {
printf("Inside fn: Argument value is %p\n", s);
printBytes("Inside fn: Bytes at address above are", (char *)s);
// This throws. *s is not a valid address.
// printf("contents: ->%s<-\n", *s);
*s = abc;
printf("Inside fn: Bytes at address above after assignment\n");
printBytes(" (should be address of \"kj\")", (char *)s);
// Now *s holds a valid address (that of "kj").
printf("Inside fn: Printing *s as string (should be kj): ->%s<-\n", *s);
}
int main() {
char str[256];
printf("size of ptr: %zu\n", sizeof(void *));
strcpy(str, "AAAAAAAA"); // 9 defined bytes
printf("addr of \"kj\": %p\n", abc);
printf("str addr: %p (%p)\n", &str, str);
printBytes("str contents before fn", str);
printf("------------------------------\n");
// Paramter type does not match! Illegal code
// (6.5.16.1 of the latest public draft; incompatible
// types for assignment).
fn(&str);
printf("------------------------------\n");
printBytes("str contents after fn (i.e. abc -- note byte order!): ", str);
printf("str addr after fn -- still the same! --: %p (%p)\n", &str, str);
return 0;
}
What you have here is simply Undefined Behaviour.
The parameter to the function is declared as pointer-to-pointer-to-char. The argument passed to it is pointer-to-array-of-256-char. The standard permits conversions between one pointer and another but since the object that s points to is not a pointer-to-char, dereferencing the pointer is Undefined Behaviour.
n1570 S6.5.3.2/4:
If an invalid value has been assigned to the pointer, the behavior of the unary * operator is
undefined.
It is futile to speculate how Undefined Behaviour will play out on different implementations. It's just plain wrong.
Just to be clear, the UB is in this line:
*s=abc;
The pointer s does not point to an object of the correct type (char*), so the use of * is UB.
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 .