Pointers to constants in C - c

I compiled the following code:
#include <stdio.h>
int main(void) {
// your code goes here
char *consta = "ABC";
printf("Use of just const: %c\n", consta );
printf("Use of const[1]: %c\n", consta[1]);
printf("Use of whole string: %s", consta);
return 0;
}
However, the output that I get is:
Use of just const: P
Use of const[1]: B
Use of whole string: ABC
The second printf and the third printf function calls work as expected however, I was expecting 'A' to be printed instead of 'P' in the first call to printf.

consta is a pointer to a character. The formatting specifier %c expects an argument of type char (character)†, not char* (pointer to character). Your code exhibits undefined behavior. Try to dereference consta instead:
printf("Use of just const: %c\n", *consta);
where *consta is incidentially equal to consta[0].
† Actually, the argument is of type int and is converted to unsigned char by printf(). This has to do with argument promotion rules that apply to functions with variable arguments; an argument to printf() of type char is promoted to int before passing it to printf(), which is why printf() has to promote it back. For most programs the difference does not matter.

consta is pointer containing the address of a string.
You're telling printf to treat that as a character, which is undefined behavior. Pointers are usually implemented as storing the address as a number, so it will typically print the ASCII value of that address.
You want to pass the value at that address (which the pointer points to) by writing *consta.

char *consta = "ABC";
is a pointer to char pointing to "ABC", to be exact to the 1st element of "ABC", that is 'A'.
"Pointing to" means consta contains an address, here the address of the 'A'.
To print a pointer, will say an address, use the conversion specifier %p:
printf("Use of just const: %p\n", (void*) consta);

I can spot three problems with your code:
The variable consta points to a constant string so you should to make it a constant:
const char *consta = "ABC";
The second argument to the first print statement should be the first character in the string rather than a pointer:
printf("Use of just const: %c\n", consta[0]);
In the last print statement there is no final newline. This implies that there may be no output from it.
If you want your code to be standard ANSI C conformant you also need to change the line-comment (//...) to a block comment (/*...*/).
It is also a good idea to enable all warnings in your compiler. With the popular GCC compiler I use the following options:
-ansi -fsanitize=address -g -pedantic -Wall -Wfatal-errors

Related

why printf doesn't accept a pointer as an argument

why codeblocks crashes when I try to run this code :
#include <stdio.h>
#include <stdlib.h>
void main(void)
{
char *ch= "Sam smith";
printf("%s\n",*ch);
}
but it works fine when I remove *ch in printf and replace it with just ch like this
void main(void)
{
char *ch= "Sam smith";
printf("%s\n",ch);
}
shouldn't *ch mean the content of the address pointed to by ch which is the string itself, and ch mean the adress of the first element in the string? so i expected the opposite!
I use Code blocks 17.12, gcc version 5.1.0, on windows 8.1 .
*ch dereferences the pointer to yield the data it points to. Here the first character of the string.
Providing the wrong specifier to printf is undefined behaviour (passing a value where printf expects a pointer)
printf("%c\n",*c);
would print the first character, without crashing. If you want to print all the string using %c (or use putchar), loop on the characters. But that's what %s does.
As a side note, better use const to reference literal strings so no risk to attempt to modify them:
const char *ch= "Sam smith";
why codeblocks crashes when I try to run this code :
char *ch= "Sam smith";
printf("%s\n",*ch);
ch is of type char *.
The %s conversion specifier expects a char *.
You pass *ch, which is the dereferenced ch, i.e. of type char.
If conversion specifiers do not match the types of the arguments, bad things (undefined behavior) happens.
shouldn't *ch mean the content of the address pointed to by ch which is the string itself
There is no data type "string" in C, and thus no "pointer to string".
A "string", in C parlance, is an array of characters, or a pointer to an array of characters, with a null-byte terminator.
ch is a char *, a pointer to the first character of that array - a string, so to speak.
*ch is a char, the first character of that array.
In C, You do not dereference a pointer to a string, when you want to use the whole string the pointer points to. This dereferencing process would result in the first character of the respective string, which is not what you want.
Furthermore, it is undefined behavior if a conversion specifier does not match to the type of the relative argument.
Thus,
printf("%s\n",*ch);
is wrong. *ch is the first character in the string, in this case S, of type char but the %s conversion specifier expects an argument of type *char.
printf("%s\n",ch);
is correct. ch is of type *char as required by the conversion specifier %s.
So, Codeblocks "crashes" apparently because of the mismatching argument type.

Pointers and Characters Variables in C

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;
}

%d specifier for an uninitialized character array

#include <stdio.h>
int main()
{
char a[8];
printf("%d\n",a) ;
return 0;
}
For the above code the output was this :- 2686744
What is the reason behind this output?
I found that the output doesn't depend on the content of the array, but on the size of the array.I just want the explanation.
char a[8];
printf("%d\n",a);
This code has undefined behavior.
The array expression a is implicitly converted to a char* value, equivalent to &a[0]. That value is then passed to printf -- but since the %d format requires an int argument, the behavior is undefined.
If int and char* happen to have the same size, and if they're passed as function arguments using the same mechanism, then it will likely print a decimal representation of the address of (the initial element of) the array.
But don't do that. If you want to print the address:
printf("%p\n", (void*)a);
You are printing the address of the array as an integer.
If you compile with -Wall to enable warnings your compiler should complain about that.

Assign pointer type to string type

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.

Why is the character d printed when I assign a string literal to a char variable?

#include<stdio.h>
int main(void) {
char a = "any"; //any string
printf("%c", a);
getch();
}
Why always d (for %c) or 100 (for %d) gets printed? What's happening?
char a="any"; is not declaring any string. Your compiler should through error/warning. You need
const char *a = "any";
Now
printf("%c", *a);
will print character a as pointer a is pointer to the first element of the string literal any.
Your code has issues. On
char a="any";
the string literal "any" is a pointer but you are saving it in a (small) integer type. Because the value of a is (part of) an address it will have an essentially arbitrary value. On my machine it prints "T" (if I remove the getch() line because that doesn't compile).
GCC gives the following warning:
warning: initialization makes integer from pointer without a cast
and whatever compiler you are using probably tells you something similar. You should really take this warning seriously.
"something between double quotes"
Allocates memory for the string and returns a pointer to the string in memory. you need to store this pointer in a using char *a = "abc"; now 'a' is a pointer to the string abc.
printf("%s",a) this will print the entire string abc.
for a single character use single quotes 'a' in this case char a = 'b'; is correct.
printf("%c",a) this will print b.
printf("%d",a) this will print the ascii value of 'b', which is 98
In the statement
char a = "any";
the string literal "any" evaluates to the address of its first character which is of type const char *. Assigning a const char * to a char variable implicitly converts the pointer to an integer. This emits the following warning if you compile with -W gcc flag:
warning: initialization makes integer from pointer without a cast [enabled by default]
What happens next is the least significant byte of the cast integer value is assigned to the char variable a. This is a random value and cannot be predicted. On my machine, it happened to be the ascii code for the character /. On your machine, it happened to be 100, the ascii code for the character d. It is just pure chance. Nothing else.
You should assign a string literal to a const char * as:
const char *a = "any";
and print the string pointed to by a by the %s conversion specifier as:
printf("%s\n", a);
Also note that getch is not a C standard library function, so your program won't compile on a linux machine. You can use getchar for the same effect, though.

Resources