#include <stdio.h>
#include <string.h>
int main(){
// char* is a pointer
char str_a[20];
char *pointer;
char *pointer2;
strcpy(str_a, "Hello, world\n");
pointer = str_a;
printf(pointer);
pointer2 = pointer + 2;
printf(pointer2);
strcpy(pointer2, "y you guys!\n");
printf(pointer);
}
Hi, I'm following a book and have come across an program explaining pointers which I am unable to understand. The book does not seem to mention why it is this way, which means that I have to consult elsewhere to get a better understanding. The above code generates the following output:
Hello, world! (pointer)
llo, world! (pointer2)
Hey you guys! (pointer)
What I fail to understand is that the last change to the variable pointer is on line 8. Yet the value of pointer can clearly be seen to change in the last line of output.
I would expect the value of pointer2 to be He rather than llo, world! on the second line of output. The only thing that I can think of - is that on line 14, when + 2 is specified, the first two bytes of pointer is chopped (or the remaining bytes are chopped off, and the first two bytes stay the same in pointer?)
But this cannot be the case - because when I add printf(pointer) below pointer2 = pointer + 2 - the output is "Hello, world!" again rather than "He"
First of all pointer and pointer2 are not declared as pointers, there should be a '*' before those variables to declare them as pointers. Even if this is from the book, this is not correct.
What I fail to understand is that the last change to the variable
pointer is on line 8. Yet the value of pointer can clearly be seen to
change in the last line of output.
Yes! That's the point of pointers! pointer2 has the same address as pointer but plus 2 elements (remember an array variable contains the address of the first variable of that array) as assigned in "pointer2 = pointer + 2;" Therefore, the "strcpy(pointer2, "y you guys!\n");" instructions will begin to copy the characters after the "He" since pointer2 points to the first 'l'.
pointer and pointer2 basically point to the same chunk of memory. That said, the initial state is like this:
p p2
H e l l o , w o r l d \n \0
Then you overwrite the chunk under p2 and it becomes:
p p2
H e y y o u g u y s \n \0
Hope these charts make sense. When you print out a pointer it will always reach to the end of the array, which is \0.
Now, strings in c are zero-byte (\0) terminated, so when you assign str_a to pointer and print pointer the printer will go from the first address pointer points to until the terminating \0, so it will print all of the text.
But when assigning pointer2 the value of pointer plus 2, you make it point two addresses after where pointer point, and when printing it you start from the l of Hello, until the terminating \0.
And for the third one, you replace the content in the memory from where pointer2 points with "y you guys!\n", so the total string starting from two addresses (where pointer points) before would be "Hey you guys!\n", leading to the result you got.
H e l l o , w o r l d \n // start from pointer
^ pointer
H e l l o , w o r l d \n // start from pointer2
^ pointer ^ pointer2
H e y y o u g u y s ! \n // start from pointer
^ pointer ^ pointer2
In C, pointers to strings (or anything) point to the start of the string, not the end.
For strings, the end is identified by the presence of a null ('\0') character.
So, if you have a pointer to a string, say, *p pointing to "Hello", this is how the string is layed out in memory:
<*p points to 1000>
| 1000 | 1001 | 1002 | 1003 | 1004 | 1005 |
H e l l o \0
Now, if you add 2 to p, p now points to 1002:
| 1002 | 1003 | 1004 | 1005 |
l l o \0
So, obviously, accessing p as a string pointer will give you "llo". If you want to make the string end prematurely, you should set the target character to be '\0':
char mystr[10] = "Hello";
char *p = mystr;
*(p+2)='\0';
Hell, you don't even need a pointer to do that. You can just do mystr[2] = '\0';
Related
int main(){
printf("hello world"+2);
}
test.c:32:25: warning: adding 'int' to a string does not append to the string
[-Wstring-plus-int]
printf("hello world"+2);
~~~~~~~~~~~~~^~
test.c:32:25: note: use array indexing to silence this warning
printf("hello world"+2);
^
& [ ]
1 warning generated.
alpha#Desktop % ./a.out
llo world%
So this is what I am getting. And if I increase the number then it is simply slicing the string by that.Can anyone explain this output and why it's happening to me?
In the C and C++ languages, every string that has been defined with double quotes is of type char* (pointer to char) as a statically allocated char array. When you call printf() on such string it does something like this:
void printf(char* str) {
while(*str!= '\0') {
// write the current character to stdout
write(STDOUT_FILENO, str, sizeof(char));
str ++;
}
}
I don't know if it really is written that way, indeed it probably isn't, the functionality is the same. It iterates over the string until it finds the null-terminator ('\0'). All pointers are almost equivalent to long and when you add a number to them, it increments their underlying value with sizeof(type), where type is the type of value the pointer points towards. Thus, when you add a number to "Hello World", makes printf() think your string starts on a different memory address and prints 'llo World'.
If you want to print the string with the value '2' appended to the end of it, as #Elliott Frisch stated, you would use print("Hello World%d", 2).
I would suggest looking at sprintf() and strcat() for string concatenation in C.
In C, what we might think of as a string is actually an array of characters. What you pass to printf() in both cases is a pointer to the start of such an array. You can do arithmetic with pointers, which is what you are doing here.
Here's some clarification.
#include <stdio.h>
int main(void) {
// A
printf("Hello, world!\n");
// B
printf("Hello, world!\n" + 2);
}
Output:
Hello, world!
llo, world!
In case A, you point to the start of an array containing the H character, and it reads until the last one (which is in fact a 'this is the end'-character: \0).
⬇️
H
e
l
l
o
,
w
o
r
l
d
!
\n
\0
In case B, you add 2 to the pointer before passing it to printf(). Now printf() starts reading here:
⬇️
H
e
l
l
o
,
w
o
r
l
d
!
\n
\0
This is what causes your 'slice'.
#include<stdio.h>
int main(void)
{
char s[] = "Hsjodi", *p;
for(p=s; *p; p++)
--*p;
puts(s);
return 0;
}
This is a code snippet given in chapter 13 exercise of
K N King
C Programming: A Modern Approach, 2nd Edn 2008. The question asks for the output.
I was not able to understand and depict the output visually so I coded it in editor and executed it.
This code gives Grinch as output. Can anyone explain why? I'm really having hard time understanding pointers and Strings in C.
No worries, with pointers you just need to remember that *p means whatever is inside p
and p alone means the memory address
so with that in mind,
Remember the ASCII TABLE, this program is operating chars, and because a string is a group of chars, every char has an address memory which happens to be next from the other one.
Have in mind that every char has a number asigned, using -- means to rest -1 to the number asigned of that char.
So with the string or char group Hsjodi the for just rests -1 to every character
Let's go through...
H in ASCII means 48, now do --*p which is -1 so now it's 47 the char G
s in ASCII means 115, now do --*p which is -1 so now it's 114 the char r
j in ASCII means 106, now do --*p which is -1 so now it's 105 the char i
o in ASCII means 111, now do --*p which is -1 so now it's 110 the char n
d in ASCII means 100, now do --*p which is -1 so now it's 99 the char c
i in ASCII means 108, now do --*p which is -1 so now it's 107 the char h
which ends up like this Grinch
for(p=s; // P is a pointer to the first character in S ('H')
*p; // Keep the loop going as long as the character at P is not zero (which, in C, marks the end of the string)
p++) // Each pass, move P to the next character s... j... o... etc
--*p; // Take the value at pointer P, and decrease it by one.
// (H ==> G, s ==> r, the previous letter alphabetically)
The --*p means that the pointer p will first be dereferenced and then decremented by 1. At the beginning of the for loop, the pointer p is assigned to the start of the char string s. Dereferencing p will give you H, decrementing that by 1 will give you G.
The loop does this for all the characters in the string, so the decrementing all the characters in the loop by 1 will give you "Grinch" as the final output.
First, s is a char array and p is a char pointer.
In the for loop, the value of s, which is the address of the first element of the array, is assigned to p.
The judgment condition of the loop is the dereference of p. It is worth noting that the s array has 7 elements, including 6 letters and a null character \0. When the loop reaches the end, a null character in p dereference will cause the loop to abort.
After each round of the loop, p will increase automatically, that is, point to the next character.
The statements in the loop body need to be aware that the dereference symbol has a higher priority than the decrement symbol.
In other words, first dereference p as a character in the string, and then decrement it. The object of subtraction is the ascii code of the character, and the corresponding letter is the previous letter. So the output is Grinch.
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
void print_reverse(char *s)
{
size_t len=strlen(s);
char *t=s+len-1;
printf("%s %s\n",t,s);
while(t>=s){
printf("%c",*t);
t=t-1;
}
puts("");
}
int main(){
print_reverse("Hello");
}
Can anyone tell how char *t=s+len-1; and while(t>=s) works. I cant understand how a number can be added to pointer and how the pointers are compared in while loop. This program is for reversing a string in c.
Lets do this line by line:
print_reverse("Hello");
void print_reverse(char *s)
Now s points to a string that contains:
- - ----+----+----+----+----+----+----+---- - -
| H | e | l | l | o | \0 |
- - ----+----+----+----+----+----+----+---- - -
^
s
That last character is called the string "NUL" terminator because "NUL" is the name of the character with ASCII value zero (all ASCII values that are not printable have three letter names).
size_t len=strlen(s);
Now len has a value of five. Notice it does not include the "NUL" terminator so even though the string takes 6 bytes the length is five.
char *t=s+len-1;
Now t has a value of s+4. If you count the memory locations this is what you get:
- - ----+----+----+----+----+----+----+---- - -
| H | e | l | l | o | \0 |
- - ----+----+----+----+----+----+----+---- - -
^ ^
s t
Note that s+strlen(s) would point to the "NUL" terminator.
printf("%s %s\n",t,s);
That printf should print Hello o
while(t>=s)
This while loop will continue as long as t>=s which means it will do the body of the loop for every character, including the one where s is pointing.
printf("%c",*t);
This prints the contents of the memory that t is pointing at. It starts with the o and continues backwards towards the H.
t=t-1;
That the part that moves t backwards. Eventually t will be past s and then the loop will end. When the loop finishes it will look like this:
- - ----+----+----+----+----+----+----+---- - -
| H | e | l | l | o | \0 |
- - ----+----+----+----+----+----+----+---- - -
^ ^
t s
Then there is this one final line:
puts("");
That prints an empty string and a final linefeed - there wasn't a linefeed in the string but we needed one so this is a way to do that.
Pointer Arithmetic
When a pointer points into an array, adding integers to the pointer or subtracting integers from the pointer moves the pointer back and forth within the array.
This function should be passed a char *s that points to a string, which is an array of characters ending in a null character ('\0'). Then size_t len = strlen(s); sets len to the size of this string, and char *t = s+len-1; sets t to point to the last character before the null character.
Then, in the loop t=t-1; moves t backward.
Unfortunately, this loop uses t>=s as its control condition. This is intended to stop when t has been moved to the character before s, meaning it has gone back before the start point. However, the C standard only defines pointer arithmetic for elements within the array plus a special position at the end of the array. If this function is passed an s that points to the beginning of an array, then the loop will eventually make t point before the array, and the C standard does not define the resulting behavior.
Other Things to Know About Pointer Arithmetic
Any object may be treated as an array of one element. If you have some type T and some object T x;, you may set a pointer T *p = &x;, and then it is allowed to advance the pointer by one element, p = p+1;. Dereferencing that pointer with *p is not defined, but you can compare it, as in &x == p, or you can subtract one from it.
If print_reverse were passed a pointer into an array beyond the beginning, then its loop would be okay. However, that is now how it is used in the example code; print_reverse("Hello"); is not good code.
Any object may be treated as an array of characters. You can convert a pointer to any object to a pointer to unsigned char and then examine the bytes that make up an object. This is used for special purposes. You should not use it in general code while you are learning C, but you should be aware it exists.
I have a piece of code that has the following lines:
char* someString = "Blah"
char* someOtherString = someString;
if (someString) {
while (*someOtherString) {
printf("%d\n",someOtherString);
++someOtherString;
}
--someOtherString;
}
This prints out:
4206692
4206693
4206694
4206695
How does it even work? I get that it goes through the if statement as true because someString can be interpreted as a true condition, but how does it exit the while loop?
When I type the while loop by itself like so, I the loop goes infinitely:
while (*someOtherString) {
printf("%d\n",someOtherString);
++someOtherString;
}
Thanks for help in advanced!
The while loop exits when it finds the NUL character at the end of the "string".
Working :
In C, declaring and assigning constant strings inside double-quotes declares a null-terminated string. Memory equal to the
number of characters in side the double-quotes + 1 (for the trailing NUL character) is allocated. Each of the characters is stored sequentially in the memory block and a NUL character is automatically assigned to the end of the memory block.
Thus "Blah" is stored in memory as
B L A H \0
Intially someOtherString and someString both point to B.
someOtherString is incremented to point to the next character in each iteration of the while loop. So after 4 iterations it ends up pointing to the null character.
A while loop running on un-initialised data could run for a large
number of iterations as there is no guarantee that it will encounter a
NUL character (byte = 0x00).
Finally a list of popular functions and extensions for processing strings in C.
This is just a technique to scan through a string.
When you just tell char *string1 = "hello" the starting address of the string will be stored inside the variable char *string1 and not the string. One practice is to assign a pointer to NULL when it is not used, instead allowing the old address values in it, which now is not valid. Therefore if at some point we did string1 = NULL, then the if (string1) will be false, becaues NULL evaluates to 0.
a1 a2 a3 a4 a5 a6
+-----+-----+-----+-----+-----+-----+
string1 = | h | e | l | l | o | \0 |
+-----+-----+-----+-----+-----+-----+
Whereas when we do *string1 it is basically in the form *(string + x). Depending on the type of the pointer string1 , x elements will be skipped first, then * will do the dereferencing at the location, x elements away from the address what is stored in string1.
a1 a2 a3 a4 a5 a6
+-----+-----+-----+-----+-----+-----+
string1 = | h | e | l | l | o | \0 |
+-----+-----+-----+-----+-----+-----+
^
|
+-------------+
|
*(string1 + 3) same as string1[3]
Therefore doing *string1 will fetch the value pointed by the address stored in string1.
Therefore
if (string1)
{
while (*string1)
{
count++;
string1++;
}
}
This will enter the if iff the address stored in the string is not NULL, ie some valid address is assigned (if we follow the convention to assign NULL to unused). *string will be true until the address stored in string1 in a specific iteration points to a non-zero value. C strings are terminated with a NUL character which is '\0' and has an ASCII value 0. In each iteration we do string1++, this will increment the address value stored, and after each increment the value of string1 will point to the next element adjacent (first a1 then a2 etc). When it points to the address where '\0' is stored, *string1 will be 0 and while (*string1) is false thus breaks out of the loop.
Your string literal is stored in memory like:
{'B', 'l', 'a', 'h', '\0'}
...where '\0' is the null character (i.e. a character with a value of 0 when interpreted as an integer).
So eventually (after 4 increments), *someOtherString will evaluate to 0, which will be interpreted as false and end the loop.
I'm not sure how you're getting the infinite loop. Your cut-down versions works just fine in ideone: http://ideone.com/4fTDJb
The code snippet is:
char c[]="gate2011";
char *p=c;
printf("%s",p+p[3]-p[1]);
The output is:
2011
Can anyone explain how it came?
-----Thanks in advance-----
Going through each line in turn:
char c[] = "gate2011";
Let's assume that array c is located at memory address 200.
char *p = c;
p is now a pointer to c. It therefore points to memory address 200. The actual content of p is "200", indicating the memory address.
printf("%s", p + p[3] - p[1]);
The value of p is 200 when we treat it like a pointer. However, we can also treat it like an array. p[3] gets the value of the 4th item in the string, which is "e". C stores characters as their ASCII value. The ASCII value of "e" is 101.
Next, we get the value of p[1]. p[1] == "a", which has an ASCII value of 97. Substituting these into the function:
printf("%s", 200 + 101 - 97);
That evaluates to:
printf("%s", 204);
At memory address 204, we have the string "2011". Therefore, the program prints "2011".
I'm not sure why you'd want to do something like this, but anyway, this is what's happening.
p + p[3] - p[1]
Here you are taking a value of one pointer, and adding the value of the char at position 3, and then subtracting the value of the char at position 1. The char values are being implicitly cast to numerical values before doing the addition and subtraction.
If p is location 1000, then the sum 1000 + 101(ASCII for e) - 97(ASCII for a) will be made. Therefore the result is a pointer to location 1004 in memory. The %s in the printf then subsitutes the string that starts at this location, and ends with the special character '\0'. So the string is effectively clipped to "2011" (the first 4 letters are missed because 101 - 97 = 4).
If this still doesn't make sense, I'd suggest you have a good look at how arrays in C work.
What have you expected? Why not?
p[3]-p[1] = 'e'-'a' = 4
p+4 = "2011"