I am reading Head First C book and in pointers chapter(and pointer arithmetic) i couldnt understand something.
I have to write arrays like this to print its 3rd element:
main(){
int drinks[] = {4, 2, 3};
printf("3rd order: %i drinks\n", *(drinks + 2));
}
But when using pointer i need to write like this
void skip(char*);
int main() {
char *msg_from_amy="dont call me";
skip(msg_from_amy);
}
void skip(char *msg){
puts(msg+6);
}
Shouldnt i need to write *(msg+6) to access 7th element? msg holds an address and msg+6 means ahead of 6 bytes from begining. so it is still an address, i need to write *(msg+6) to access stored value in that address from my perspective but it doesnt work. But why quoted one right answer, why i cant figure out.
Edit: Actually i asked wrongly my question. And edited code snippets. Here is output of:
puts(msg+6);
printf("%c\n", *(msg+6));
printf("%s\n", *(msg+6));
all me
a
I expected get "all me" output from 2nd printf like 1st one. But i think i understand the reason. its difference of puts and printf argument list. Thx for answers.
Btw why 3rd printf prints just a blank character?
I have to write arrays like this to print its 3rd element:
main(){
int drinks[] = {4, 2, 3};
printf("3rd order: %i drinks\n", *(drinks + 2));
}
No, you don't have to do that, and it is very non-idiomatic. Most people would use
printf("3rd order: %i drinks\n", drinks[2]);
Moving on ...
void skip(char *msg){
puts(msg+6);
}
Shouldnt i need to write *(msg+6) to access 7th element?
Yes, *(msg+6) to access 7th element or, better, msg[6]. But you're not trying to access the 7th element. You are providing to puts the substring that starts at the 7th element. msg+6 is just fine for that.
Here is output of:
puts(msg+6);
printf("%c\n", *(msg+6));
printf("%s\n", *(msg+6));
all me
a
I expected get "all me" output from 2nd printf like 1st one
I don't see why. The %c formatting directive converts and prints one character, which is good because that's what you pass as the corresponding argument. It's not about a difference between puts and printf. Rather, it's mostly about the deep difference between msg+6 and *(msg+6).
Btw why 3rd printf prints just a blank character?
No one can say. The behavior of your third printf call is undefined because the formatting directive %s, which expects a char * argument, is not correctly type matched with the corresponding argument *(msg+6), which is a char. Anything could happen. And this underscores my previous point: there is no deep difference in this regard between puts and printf. You appear to want:
printf("%s\n", msg+6);
I expected get "all me" output from 2nd printf like 1st one.
The %c specifier is intended to print exactly one character. Furthermore, it's impossible to go to msg+7 from *(msg+6).
Btw why 3rd printf prints just a blank character?
Because %s expects a pointer. *(msg+6) is not a pointer.
You should compile with -Wall -Wextra. That will make the compiler warn you about a lot of stuff.
If you need the value that msg points to, you need to deference it using the * operator. So, if you want to get the sixth element pointed by msg, you need to advance by 6 and then deference it. The problem with printf("%s\n", *(msg+6)); is that %s expects a string, but *(msg+6) is a character. You can try to change %s with %c.
Remember that a string in c is a collection of characters ended by the null character '\0'.
Related
Using pointers, I am able to get to the actual character('i' in ElGenerico) that I want to print. But some weird character is getting printed on the screen, rather than my desired character.
#include<stdio.h>
int main()
{
char *name[]={"Sami","Kevin","ElGenerico"};
printf("%c",(*(name+2)+7));
return 0;
}
With my use of %s output specifier, the output of this code is "ico".
But I want to print only the character 'i'. So I tried using %c, instead of %s. It doesn't work. Instead, a double headed arrow is printed.
Can anyone please tell me where I am going wrong?
I recommend using bracket notation for improved readability.
Initially, you had this:
printf("%c",(*(name+2)+7));
You would still need to dereference with * to get the desired output.
That would give you this:
printf("%c",*(*(name+2)+7));
However, that's still a bit confusing and not very readable. You could make it much cleaner by using bracket notation, like this:
printf("%c", name[2][7]);
Now there's much less room for error and you still get the expected output.
Your final code would look something like this:
#include <stdio.h>
int main()
{
char* name[] = {"Sami", "Kevin", "ElGenerico"};
printf("%c", name[2][7]);
return 0;
}
You are pointing to the wrong address. Use this instead:
printf("%c",(*(name[2]+7)));
Since you are referring to the third element in the name array, you can use
name[2]
Then you wanted to put the 7th element of the word ElGenerico, hence we need to add 7 to the address:
name[2] + 7
After we get the correct address, then we print out the value of that address, and we use the * sign:
*(name[2] + 7)
printf("%c",*(*(name+2)+7));
I used this, and it's solved, thanks for the help #David and #rcs...
Why do I need an ampersand before the array in the printf statement here, but any other time ampersand is only used in scanf?
Completely new so if you could explain as simply as possible that would help.
int main(void) {
char word[1];
scanf("%s", &word[0]);
printf("%s", word[0]);
return 0;
}
You do need one. It's incorrect without one and leads to undefined behavior, which may cause anything to happen (even the program appearing to work correctly). Also, word[1] can only hold the null terminator of an empty string, any more than that and it will cause the buffer to overflow, also causing undefined behavior. It should be:
int main(void) {
char word[10]; // or any value that is big enough for the input that your anticipating
scanf("%9s", &word[0]);
printf("%s", &word[0]);
return 0;
}
And of course you can replace &word[0] with word.
Also note that I put %9s instead of just %s for the scanf call, which means that it will get at most 9 characters, which with the added null terminator fits into the word[10] that we have as an example. This way you don't get undefined behavior if the user enters something that's too big and instead it would just truncate that input.
word[0] is the first character.
the & sign is used to get a pointer to such character.
scanf("%s", &word[0]);
printf("%s", word[0]);
In C, a string (addressed by %s in above statements) is defined as an array. Your declaration of "word":
char word[1];
declares an array, so that array can be a string (I wrote can, because it's a very short string...). If you use the identifier alone, "word", the compiler uses a pointer to the first element of the array. Hence:
scanf("%s", word);
printf("%s", word);
are both correct. But if you use an index into the array, like "word[0]", then you are no more using the array per se, but instead an element of it. This notation does not generate a pointer, but your above statements do need a pointer. So you can use an "&" to get a pointer.
Conclusion: if you have a string, use its simple name without indexing inside the array. Using the ampersand makes it clear that we pass a reference, but "&word[0]" is ugly and, moreover, everybody should know that scanf() writes into its arguments.
I'm trying to read the characters of a character array by number in c. I've stripped the program down to isolate the problem. I know this is about my misunderstanding of how arrays and memory works and I am ready to be called clueless but I would like to know what I am misunderstanding here. Here is what I have:
#include <stdio.h>
int main(int argc, char **argv) {
char buffer[] = "stuff";
printf("buffer is %s\n", buffer);
printf("first character of buffer is %s", (char)buffer[0]);
return 0;
}
You have to write the correct format specifier. Now you used %s ...what happens?
It looks for an string which is null terminated. But it doesn't find one. So it simply cant put anything in the output . That's it.
Use %c instead.
In C there is a very big difference between a character and a string.
A character is simply a number in a range of 256 different options.
A string is not really a type of its own, it is merely an array of chars (which, in C, is simply evaluated as a pointer to the first character of the string).
Now, when you type buffer[0], this is evaluated to the value at the beginning of the string (first value in the array). Indeed, this is of char type (and therefore you do not need the (char) casting, because this will not do anything in the case of your code).
What you need is to tell printf() how to evaluate the input that you give it. %s is for a string (an array of chars). But note and remember that buffer[0] is not an array of chars, but rather a char.
So you actually want to use %c, instead of %s. This tells printf() to evaluate the parameter as a char type.
What your code currently does is take the value buffer[0] (which is just a number) and consider it as a pointer to a location in memory where a string is kept, and printf() tries to print this string. But this memory location is simply invalid. It is not a location you've accessed before.
In conclusion you want:
printf("first character of buffer is %c", (char)buffer[0]);
or even simpler:
printf("first character of buffer is %c", buffer[0]);
For other specifiers of the printf() function, look here:
http://www.tutorialspoint.com/c_standard_library/c_function_printf.htm
If you want to print only a single char use %c format.
printf("first character of buffer is %c\n", (char)buffer[0]);
#include <stdio.h>
#define slice(bare_string,start_index) #bare_string+start_index
#define arcane_slice(bare_string,start_index) "ARCANE" #bare_string+start_index
int main(){
printf("slice(FIRSTA,0)==> `%s`\n",slice(FIRSTA,0));
printf("slice(SECOND,2)==> `%s`\n",slice(SECOND,2));
printf("slice(THIRDA,5)==> `%s`\n",slice(THIRDA,5));
printf("slice(FOURTH,6)==> `%s`\n",slice(FOURTH,6));
printf("slice(FIFTHA,7)==> `%s`\n",slice(FIFTHA,7));
printf("arcane_slice(FIRSTA,0)==> `%s`\n",arcane_slice(FIRST,0));
printf("arcane_slice(SECOND,2)==> `%s`\n",arcane_slice(SECOND,2));
printf("arcane_slice(THIRDA,5)==> `%s`\n",arcane_slice(THIRDA,5));
printf("arcane_slice(FOURTH,6)==> `%s`\n",arcane_slice(FOURTH,6));
printf("arcane_slice(FIFTHA,7)==> `%s`\n",arcane_slice(FIFTHA,7));
return 0;
}
OUTPUT:
slice(FIRSTA,0)==> `FIRSTA`
slice(SECOND,2)==> `COND`
slice(THIRDA,5)==> `A`
slice(FOURTH,6)==> ``
slice(FIFTHA,7)==> `slice(FIFTHA,7)==> `%s`
`
arcane_slice(FIRSTA,0)==> `ARCANEFIRST`
arcane_slice(SECOND,2)==> `CANESECOND`
arcane_slice(THIRDA,5)==> `ETHIRDA`
arcane_slice(FOURTH,6)==> `FOURTH`
arcane_slice(FIFTHA,7)==> `IFTHA`
I have the above C code that I need help on. I am getting weird behaviour from
the function-like macro slice that is supposed to 'slice' from a passed index
to the end of the string. It does not slice in the real sense but passes
a pointer from a certain point to printf which starts printing from that
address. I have managed to figure out that in arcane_slice the strings
are concatenated first then 'sliced'. I also have figured out that when start_index
is equal to 6 printf starts printing from the null byte and that is why
you get the 'empty' string. The strange part is when start_index is 7. It prints
the first argument to printf(interpolator string) concatendated with the passed bare string in both.
arcane_slice and slice(as shown in the 5th and 10th lines in the output)
Why is that so?
My wildest guess is that when the start_index exceeds the length of the strings,
the pointer points to the start of the data segment in the program's address space. But
then you could counter that with "why didn't it start printing from FIRSTA"
Not any "data segment", the stack. This is what I remember: when C calls a function it first puts data on stack, first variable arguments, then the format, all being the addresses to the memory sequentially allocated with your text. In that block of memory, the last argument (c-string) goes first, and the first goes last, thus:
Memory:
"FIFTHA\0slice(FIFTHA,7)==> `%s`\n\0"
Arguments:
<pointer-to-"FIFTHA"> <pointer-to-"slice...">
Since you overincrement the first one it skips the '\0' character and points at the format as well.
Try to experiment with this with more placeholders, like
printf("1: %s, 2: %s\n", slice(FIFTHA,7), slice(FIFTHA,6));
slice(bare_string,start_index) #bare_string+start_index
you are passing a string and bare_string stores the starting address of string which you have passed and then you returning changed pointer location which is bare_string+start_index
char str[6]="Hello";
char *ptr =str;
printf("%s\n",str);//prints hello
printf("%s\n",str+1);//prints ello
printf("%s\n",str+2);//prints llo
printf("%s\n",str+3);//prints lo
printf("%s\n",str+4);//prints o
printf("%s %c=%d \n",str+5,*(str+5),*(str+5));//prints Null
printf("%s %c=%d \n",str+6,*(str+6),*(str+6));//prints Null or may be Undefined behavior
printf("%s %c=%d \n",str+7,*(str+7),*(str+7));//prints Null or may be Undefined behaviour
the same scenario is happing in your case.
Test Code:
#include<stdio.h>
main()
{
char str[6]="Hello";
char *ptr =str;
printf("%s\n",str);//prints hello
printf("%s\n",str+1);//prints ello
printf("%s\n",str+2);//prints llo
printf("%s\n",str+3);//prints lo
printf("%s\n",str+4);//prints o
printf("%s %c=%d \n",str+5,*(str+5),*(str+5));//prints Null
printf("%s %c=%d \n",str+6,*(str+6),*(str+6));//prints Null or may be Undefined behavior
printf("%s %c=%d \n",str+7,*(str+7),*(str+7));//prints Null or may be Undefined behaviour
}
You have answered your question yourself. "FIFTHA"+7 gives you a pointer outside the string object, which is undefined behavior in C.
There's no easy way to get a more Python-like behavior for such "slices" in C. You could make it work for indexes up to a certain upper limit by adding a suffix to your string, full of zero bytes:
#define slice(bare_string,start_index) ((#bare_string "\0\0\0\0\0\0\0")+(start_index))
Also, when using macros, it's good practice (and avoids bugs too) to use parentheses excessively.
#define slice(bare_string,start_index) ((#bare_string)+(start_index))
#define arcane_slice(bare_string,start_index) (("ARCANE" #bare_string)+(start_index))
How can I make this print properly without using two printf calls?
char* second = "Second%d";
printf("First%d"second,1,2);
The code you showed us is syntactically invalid, but I presume you want to do something that has the same effect as:
printf("First%dSecond%d", 1, 2);
As you know, the first argument to printf is the format string. It doesn't have to be a literal; you can build it any way you like.
Here's an example:
#include <stdio.h>
#include <string.h>
int main(void)
{
char *second = "Second%d";
char format[100];
strcpy(format, "First%d");
strcat(format, second);
printf(format, 1, 2);
putchar('\n');
return 0;
}
Some notes:
I've added a newline after the output. Output text should (almost) always be terminated by a newline.
I've set an arbitrary size of 100 bytes for the format string. More generally, you could declare
char *format;
and initialize it with a call to malloc(), allocating the size you actually need (and checking that malloc() didn't signal failure by returning a null pointer); you'd then want to call free(format); after you're done with it.
As templatetypedef says in a comment, this kind of thing can be potentially dangerous if the format string comes from an uncontrolled source.
(Or you could just call printf twice; it's not that much more expensive than calling it once.)
Use the preprocessor to concatenate the two strings.
#define second "Second%d"
printf("First%d"second,1,2);
Do not do this in a real program.
char *second = "Second %d";
char *first = "First %d";
char largebuffer[256];
strcpy (largebuffer, first);
strcat (largebuffer, second);
printf (largebuffer, 1, 2);
The problem with using generated formats such as the method above is that the printf() function, since it is a variable length argument list, has no way of knowing the number of arguments provided. What it does is to use the format string provided and using the types as described in the format string it will then pick that number and types of arguments from the argument list.
If you provide the correct number of arguments like in the example above in which there are two %d formats and there are two integers provided to be printed in those places, everything is fine. However what if you do something like the following:
char *second = "Second %s";
char *first = "First %d";
char largebuffer[256];
strcpy (largebuffer, first);
strcat (largebuffer, second);
printf (largebuffer, 1);
In this example the printf() function is expecting the format string as well as a variable number of arguments. The format string says that there will be two additional arguments, an integer and a zero terminated character string. However only one additional argument is provided so the printf() function will just use what ever is next on the stack as being a pointer to a zero terminated character string.
If you are lucky, the data that the printf() function interprets as a pointer will a valid memory address for your application and the memory area pointed to will be a couple of characters terminated by a zero. If you are less lucky the pointer will be zero or garbage and you will get an access violation right then and it will be easy to find the cause of the application crash. If you have no luck at all, the pointer will be good enough that it will point to a valid address that is about 2K of characters and the result is that printf() will totally mess up your stack and go into the weeds and the resulting crash data will be pretty useless.
char *second = "Second%d";
char tmp[256];
memset(tmp, 0, 256);
sprintf(tmp, second, 2);
printf("First%d%s", 1,tmp);
Or something like that
I'm assuming you want the output:
First 1 Second 2
To do this we need to understand printf's functionality a little better. The real reason that printf is so useful is that it not only prints strings, but also formats variables for you. Depending on how you want your variable formatted you need to use different formatting characters. %d tells printf to format the variable as a signed integer, which you already know. However, there are other formats, such as %f for floats and doubles, %l% for long integers, and %s for strings, or char*.
Using the %s formatting character to print your char* variable, second, our code looks like this:
char* second = "Second";
printf ( " First %d %s %d ", 1, second, 2 );
This tells printf that you want the first variable formatted as an integer, the second as a string, and the third as another integer.