Hello Everyone I just want to clarify a doubt regarding pointers.So that I can know whether I understood it correctly or not.
void main ()
{
char c[10]="COMPUTERS";
printf("The first is %d\n",c); //1
printf("The second is %f\n",c); //2
printf("The third is %u\n",c); //3
printf("The fourth is %s\n",c); //4
printf("The fifth is %c\n",c); //5
}
The first printf will print the address of first location of character array 'c',
Similarly second printf will also try to print the address in float form.
The third printf will print the address again.
While the fourth printf will print the character array.
My doubt is associated with the 5th printf. It is printing random values or sometimes no values is it because the value of 'c' is memory address of first character of array 'c' and I am trying to print that value as a character?
all of those prints are undefined behavior except the %s one. the weird behavior you are seeing with %c format specifier is due to underlying casts on the adress of the pointer which can change from running it one time to the next.
if you want to print out the adress the pointer points to use %p like this:
printf("address: %p\n", (void *)c);
(These are not "doubts", they are questions or uncertainties perhaps).
All of those except %s are undefined behavior, since they all mis-match the actual type of the value provided (char *) with the formatting specifier.
printf("The fifth is %c\n",c[0]);
This makes sense. Printing the first character of the array.
Trying to print the address just as a character makes no sense.
Only this printf() is good
printf("The fourth is %s\n",c);
The rest of the printf()'s have undefined behavior.
The first printf will print the address of first location of character array 'c',
Strictly speaking, the first printf will invoke undefined behavior since you are using the wrong format specifier to print a pointer. But yeah it will probably print the address on most systems.
Similarly second printf will also try to print the address in float form.
No it will just give you some binary goo. You never convert the address to a float format, you only attempt to print it as if it was. This is completely undefined behavior.
The third printf will print the address again.
Same as 1. Undefined behavior, but yeah, it will probably print the address...
While the fourth printf will print the character array.
Yes.
My doubt is associated with the 5th printf. It is printing random values or sometimes no values is it because the value of 'c' is memory address of first character of array 'c' and I am trying to print that value as a character?
Again, undefined behavior. It can print anything.
Theoretical analysis:
printf("The first is %d\n",c); // undefined behavior by the standard
printf("The second is %f\n",c); // undefined behavior by the standard
printf("The third is %u\n",c); // undefined behavior by the standard
printf("The fifth is %c\n",c); // undefined behavior by the standard
Practical analysis:
printf("The first is %d\n",c); // requires sizeof(void*) == sizeof(int)
printf("The second is %f\n",c); // requires sizeof(void*) == sizeof(double)
printf("The third is %u\n",c); // requires sizeof(void*) == sizeof(unsigned int)
printf("The fifth is %c\n",c); // different between big-endian and little-endian
Detailed practical analysis:
sizeof(void*) < sizeof(...) will potentially yield a memory access violation during runtime
sizeof(void*) > sizeof(...) will yield different printout between big-endian and little-endian
Related
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'.
int main(){
printf("the value is %d \n " ,'x'+ "x");
return 0;
}
Output
4196024
But the former one ('x') is an integer and latter one ("x")is a string .
Can I know how ? Or is it giving me a garbage value.
Literal strings have type char [N] where N is just large enough for all characters in the literal plus the terminating '\0' (namely "x" has type char[2]).
In the context of the expression 'x' + "X", the array gets converted to a pointer to its first element, then that address is added with the int value 'x'. The resulting address is passed on to printf() with an invalid conversion specification.
You have invoked Undefined Behaviour!
Try this
printf("the valus is %p\n", (void*)('x' + "x"));
Also note that the address 'x' + "x" is not part of any object in your program. Merely evaluating it is already Undefined Behaviour.
Basically,
printf("the value is %d \n " ,'x'+ "x");
invokes undefined behaviour. What you need is %p format specifier here.
Otherwise, in general,
"string" gives you the base address of the string literal
'p' gives you the ASCII value of the char representation.
So, what essentially is being done here is to print the address of the member in 'x'th element of the string "x" (which does not make much sense, practically).
For better understanding, you can re-write the print statement as
printf("the pointer is %p\n", (void *) ("x"+ 'x'));
which is equivalent to
printf("the pointer is %p\n", (void *) &("x"['x']));
Note that you don't need spaces before or after the newline in the print format.
What you are asking for in the formatted string is an integer so it is printing the integer value of the character 'x' added to the base address of the string literal "x".
'x' is 120 so if you use a memory viewer to peek at the outputted value minus 120 bytes, you will probably find an 'x' followed by a '\0' (= 0).
i am trying to print value of an array in C-language.I am using 3 format specifier for only one value of array , my problem is that i don't understand that how other two values are coming in my output .
here is my code:
int arr[6] = {3,4,42,2,77,8};
printf("%d %d %d ",arr[2]);
output :
42 3 4
According to the C Standard
If there are insufficient arguments for the format, the behavior is
undefined.
In your call of printf
printf("%d %d %d ",arr[2]);
the arguments are exhausted after the first format specjfjer. So the function call has undefined behaviour and the output can contain any garbage.
You shall write
printf( "%d ", arr[2] );
or for example
printf( "%d %d %d ", arr[2], arr[3], arr[4] );
When printf() sees three format specifiers, it looks at specific locations, either in stack memory or in CPU registers, depending on the conventions of the compiler, for three arguments.
You provided one, but some data that you have no control over exists in the other two locations, and that's what gets printed.
The other two values are garbage and don't have any meaning. The function printf requires as many arguments as there are format specifiers, so in your case three. Since you only provided one argument (arr[2]), the other two specifier 'don't know' what to print - thus gargabe will come out. Make sure to provide the required number of arguments.
If you want to print the array number by number, you will have to use a for loop.
The signature of printf is.
int printf(char*, ...);
So, you can have a variable number of arguments, then.
printf("%d %d %d ",arr[2]);
Is a valid call of the function printf.
However, because you provided no values yourself, then you will get whatever... that in your special case it seems that it printed arr[0] and arr[1].
As far as I know #define is just a string replacement and it's not a variable, so it doesn't have any memory address or something.
Suppose this code:
#include <stdio.h>
#define ONE "a"
main() {
printf("the number is: %d\n", ONE);
}
Then when I compile and run this program, I get a random string each time:
the number is: 8179551
the number is: 21127007
the number is: 57114463
...
If the #define doesn't have any memory address, then what's this value and why it's changed every time?
In your code
printf("the number is: %d\n", ONE);
is equivalent to
printf("the number is: %d\n", "a");
In fact you are printing the address of the string "a" as a decimal.
And you are getting random value in each execution that's because the address of "a" is got random address in each execution
The string "a" is a literal string and it's stored in the read only memory. The printf is printing the address of this memory
MOHAMED is right, you printing the adress of a string
what you what to do this
#define ONE 'a'
everything between two ''s are characters, only one character is allowed
This program invokes undefined behavior because the format specification doesn't match the type of argument (int versus char *).
C99, 7.19.6.1 # 9 (fprintf)
If a conversion specification is invalid, the behavior is
undefined.239) If any argument is not the correct type for the
corresponding conversion specification, the behavior is undefined.
The correct way to print an address is with %p and via a (void *) argument:
printf("the address is: %p\n", (void *)ONE);
This is my code:
double values[8], cumulative[8];
printf("Enter first decimal number: ");
scanf("%f", values[0]);
printf("values[0] = %g", values[0]);
My problem is that the scanf statement crashes the program, and the second printf is never executed. My original attempt was to fill each slot of the array with a double, but since that didn't work I simplified the program to this, but this doesn't work either.
I'm a beginner learning C, so I probably made a stupid mistake I just can't see. Any help would be appreciated, thanks!
Edit:
Okay, so apparently I need to add an ampersand to the scanf statement. But I thought an array was just a pointer to the first element of the array? Why do I have to use the ampersand?
scanf("%f", values[0]); - Here address of first element should be passed to scanf. You are passing value of first element which is a garbage value so that it crashed.
values[0] is *(values + 0), so this will give value of the first element not the address of the first element.
Do scanf("%lf", &values[0]); or scanf("%lf", (values + 0)); or scanf("%lf", values);
As it is double use %lf instead of %f.
One more problem in your program is uninitlized variables. Try to initialize the variable to zero while declaring.
double values[8] = {0};
double cumulative[8] = {0};
Acessing some wrong pointer in some place of your code will leads to 100% crash if its initiliazed to zero. Otherwise it will try to access some garbage value pointer which will leads to memory corruption, this sometimes will not crash instead will give unexpected output. But this also has a 50% chance of getting crash, which you are getting now.
scanf("%f", values[0]);
You need to pass the address of a location to store in to scanf(). It needs to be:
scanf("%f", &values[0]);
Otherwise, you're just telling scanf() to store the input value to whatever memory location is pointed at by the integer representation of the initialized value of values[0] -- which is most definitely not what you want.
The format for scanning a double is %lf; %f is for float. This is different from printf(), which confuses people — me too. You also need to pass a pointer to the variable.
If you use GCC, it should be warning you about a format mismatch. If it doesn't, you aren't compiling with enough warning options enabled (-Wall is a good start point; add -Wextra and -Werror if you can). The explicit option for checking printf() and scanf() formats is -Wformat, but it is included with -Wall.
#include <stdio.h>
int main(void)
{
double values[8];
printf("Enter first decimal number: ");
if (scanf("%lf", &values[0]) != 1)
printf("Scan failed!\n");
else
printf("values[0] = %g\n", values[0]);
return(0);
}
Note that this includes a newline at the end of the output, and also diagnoses when there is a problem (such as no data, or invalid data) on the input.
I thought an array was just a pointer to the first element of the array? Why do I have to use the ampersand?
An array is not just a pointer to the first element of the array, but when an array name is used in an expression other than as an argument of sizeof(), it changes to the pointer to the first element of the array.
You have to use the ampersand because values[0] is the value of the first element of the array, not the address of the first element of the array, and scanf() needs the address, not the value. Remember: a[i] == *(a + i) for an array name or pointer a and an index i, and note the * to dereference the pointer. If you wrote scanf("%lf", values) or scanf("%lf", values + 0), you are passing a pointer. Note that passing scanf("%lf", &values) would be a type mismatch (though the value passed as the address is the same — so it coincidentally 'works'). The type passed would be 'pointer to array of 8 double', which is not the same as 'pointer to double'.