Question about char pointers - c

I am confused with this program.
#include <stdio.h>
int main(void)
{
char* ptr="MET ADSD";
*ptr++;
printf("%c\n", ptr);
ptr++;
printf("%c\n", ptr);
}
Here's the output.
ET ADSD
T ADSD
My question is how does the pointer display the rest of the characters?

You are passing a wrong combination of parameters to printf: the %c format specification requires a char parameter, not a char*. So the result is undefined - in your case printf seems to print the whole char array, but this is just by pure chance. Use either
printf("%c\n", *ptr);
or
printf("%s\n", ptr);

You are actually trying to print as a char %c a pointer value char*. This is false. But then, I really don't understand why it prints all the chars. Are you sure you didn't use %s instead of %c?

The * operator as lower precedence over the ++ operator. Thus in your example the both lines
*ptr++;
ptr++;
have the same effect.
And you are using the wrong types in your printf statement.
Change
printf("%c\n", ptr);
to
printf("%s\n", ptr);
or
printf("%c\n", *ptr);
depending on what you want to output.
Btw, turning on compiler warnings helps in that case. E.g. the GCC prints:
d.c: In function ‘main’:
d.c:7: warning: value computed is not used
d.c:8: warning: format ‘%c’ expects type ‘int’, but argument 2 has type ‘char *’
d.c:11: warning: format ‘%c’ expects type ‘int’, but argument 2 has type ‘char *’
d.c:12: warning: control reaches end of non-void function

In C a string is a array of chars, and an array is simply a pointer to the first location of memory of the array.
So defining
char* ptr="MET ADSD";
you are declaring and initializing an array of chars, a string, by using a pointer to char,
The next trick comes if you consider this two factors:
pointers arithmetic in that using the operator ++ on a pointer increments its value, the memory address it is pointing to
char size which is almost everywhere 1 byte
So you are scaling the array along of two positions, and you print that by using %s and passing the pointer to it
EDIT I guess you put %c mistakenly in the example

If you are expecting 'E' as first and 'T' as second output. Give it like
#include <stdio.h>
int main(void)
{
char* ptr="MET ADSD";
*ptr++;
printf("%c\n", *ptr);
ptr++;
printf("%c\n", *ptr);
}

printf( ..., ptr) is passing the pointer, not the char it points to.
The correct version of the program would be:
#include <stdio.h>
int main(int argc, char* argv[])
{
const char* ptr = "MET ADSD";
ptr++;
printf("%c\n", *ptr);
ptr++;
printf("%c\n", *ptr);
return 0;
}
which will print
E
T
The output you are seeing makes no sense unless you are using %s. - %c is going to convert the value of ptr into an integer, truncate the int to 8bits (the width of a char), and print that character to the output. Not a string of characters.

Related

C - Static char array vs dynamic char array

This code compiles with a warning but prints the input string:
char staticArray[100];
scanf("%s",&staticArray);
printf("%s\n", staticArray);
Warning: format specifies type 'char *' but the argument has type 'char (*)[100]' [-Wformat]
This code also compiles with a warning but throws segmentation fault:
char* dynamicArray;
dynamicArray = (char*) malloc(sizeof(char)*100);
scanf("%s", &dynamicArray);
printf("%s\n", dynamicArray);
Warning: format specifies type 'char *' but the argument has type 'char **' [-Wformat]
I know both are wrong but, why does the first one prints the string value?
why does the first one prints the string value whereas second give segfault?
What's happening in Case I:
The type of staticArray is char [100] i.e. array of 100 char.
The type of &staticArray is char (*)[100].
The %s format specifier in scanf() expect the argument as a pointer to initial element of char array i.e. of type char *.
You are passing char (*)[100] type to scanf(), hence compiler is giving warning on this statement.
The &staticArray give you pointer to the array of type char (*)[100] which is numerically same as the base address of array.
Consider this example:
#include <stdio.h>
int main(void)
{
char staticArray[100];
printf ("staticArray: %p\n", (void*)staticArray);
printf ("&staticArray : %p\n", (void*)&staticArray);
return 0;
}
Output:
## ./a.out
staticArray: 0x7ffee4044a70
&staticArray : 0x7ffee4044a70
staticArray and &staticArray both yield a pointer to the same address1) but their type is different.
That's why when you pass &staticArray to scanf(), getting warning during compilation due to type mismatch but when scanf() called, it treat that pointer as char * and read input and store the result to given location. When printing it later, it prints the string value.
What's happening in Case II:
The type of dynamicArray is char *.
The type of &dynamicArray is char **.
So, you are passing char ** type to scanf() which expects char * when %s format specifier is used. Hence compiler is giving warning on this statement.
The pointer &dynamicArray is different from dynamicArray.
Consider this example:
#include <stdio.h>
#include <stdlib.h>
int main(void)
{
char* dynamicArray;
dynamicArray = malloc(sizeof(char)*100);
if (dynamicArray == NULL) {
exit(EXIT_FAILURE);
}
printf ("dynamicArray: %p\n", (void*)dynamicArray);
printf ("&dynamicArray : %p\n", (void*)&dynamicArray);
free(dynamicArray);
return 0;
}
Output:
## ./a.out
dynamicArray: 0x7fd615401690
&dynamicArray : 0x7ffee7ab7ad0
dynamicArray and &dynamicArray both yield different pointer.
When you pass &dynamicArray to scanf() (which read input and store the result to given location), it lead to undefined behavior2) because your program end up accessing invalid memory.
When you pass &dynamicArray to printf() with format specifier %s, printf(), it access that address to write the character string and end up accessing invalid memory, lead to undefined behavior2). Hence, you are getting segfault.
1) An array is automatically converted to a pointer to its first element but there are few exceptions to this rule (C11 Standards#6.3.2.1p3):
The array is the operand of sizeof operator.
The array is the operand of _Alignof operator.
The array is the operand of &.
The array is a string literal used to initialize an array.
2) An undefined behavior includes it may execute incorrectly (either crashing or silently generating incorrect results), or it may fortuitously do exactly what the programmer intended.
Removing the & operator in both examples will solve the warnings. I'm not sure what your intended behavior is, but they seem to work correctly upon moving the & operator. This is because arrays are inherently pointers to the first element of the array so adding & is not what you want.
Working examples(exactly the same expect for &):
char staticArray[100];
scanf("%s",staticArray);
printf("%s\n", staticArray);
and
char* dynamicArray;
dynamicArray = (char*) malloc(sizeof(char)*100);
scanf("%s", dynamicArray);
printf("%s\n", dynamicArray);

Why is this "%s" not allowed with value inside of pointer?

I know that pointer and exactly same to each other. The program below shows an error if i use %c and then loop through all the values of the string then i see no error but with %s i get an error.
Also if i use array i place of pointer and use arr[] with i see an error. Like arr[] = "Hello" and then use printf("%s", arr[]); .......i see an error too. What is wrong here?
#include <stdio.h>
#include <stdlib.h>
main()
{
char *ptr = "Hello";
printf("%d\n", ptr);
printf("%s\n", *ptr);
return 0;
}
Both calls of printf result in undefined behavior:
Passing a pointer for a parameter printed with %d is not allowed
Passing a non-pointer (in this case, that's a char) to %s is undefined behavior as well. It is likely to cause a crash because a non-pointer gets dereferenced.
In order to print a value of a pointer, cast the pointer to void*, and use %p format specifier:
printf("%p\n", ptr);
In order to print a string, pass ptr, not *ptr, to a parameter with %s format specifier:
printf("%s\n", ptr);

pointer to value in array?

So I need to have a pointer to a value in a const char array. But I can't quite get it to work without errors. Here's the code.
int main (void)
{
const char *alp = "ABCDEFGHIJKLMNOPQRSTUVWXYZ";
char *ptr = &alp[3];
printf("%s\n", ptr);
return 0;
}
Edit- Sorry for not mentioning the errors. The thing is I get tons of different errors depending on where I put different asterisks and ampersands. There is no one particular error. One of the more frequent ones I get says
"incompatible integer to pointer conversion assigning to 'char *'
from 'const char';"
In the end I just want "ptr" to be equal to a pointer pointing to "D" in the array "alp".
If you only want one character to print, change the %s to %c and dereference the pointer
printf("%c\n", *ptr);
It's true that you had a character pointer but %s tells printf to print from that pointer until it reads a null character. So we switch to %c which will print one character but it expects a value rather than a pointer to a value.
alp is a pointer to constant char.
ptr is a pointer to a non-const char.
If you want that to work out you would need to change ptr to be defined as:
char const * ptr = &alp[3];
The const is saying that you're not going to change it, but then you're trying to copy the reference to a variable without that limitation. Instead, try:
const char *ptr = &alp[3];
But note that as other posters have already suggested, this code will give you a pointer to a string beginning with the D (e.g. DEFGHI...), not just the character D.

Why don't I need to dereference a character pointer in C before printing it?

Why does this code work? I would expect that I would need to dereference ptr, printf("%s\n", *ptr); before I could print it out, but I get a Segmentation Fault if I try to do it that way.
#include <stdio.h>
int main(int argc, char *argv[])
{
char name[] = "Jordan";
char *ptr = name;
printf("%s\n", ptr);
}
Hope you guys could give me some insight.
When you print string we need starting address of string.
printf("%s\n", ptr);
^ address with %s
it prints chars till \0 nul encounter.
Whereas to print chat int .. we need value variable:
printf("%c\n", *ptr);
^ * with %c print first char
Where as in scanf() a string you always need to give address:
scanf("%s", ptr);
^ string address
Also for int scanf() a char
scanf("%c", ptr);
^ read at first location char address
Note: Scanf() need address with %c to store a scanned value in memory.
Be careful your ptr points to a constant string so you can't use in scanf.
Why Segmentation fault with following code ?
printf("%s\n", *ptr);
When you do like this, because of %s printf interprets *ptr as an address, but it's actually not an address and if you treat it as address it points to some location that is read protected for your program(process) So it causes a segmentation fault.
Your ptr via name points to some constant string in memory ("Jordan") as in below diagram:
name 2002
┌─────┬─────┬─────┬─────┬─────┬─────┬─────┬─────┬─────┬─────┐
│ 'J' │ 'o' │ 'r' │ 'd' │ 'a' │ 'n' │'\0' │ ........
└─────┴─────┴─────┴─────┴─────┴─────┴─────┴─────┴─────┴─────┘
^
|
ptr = name
==> ptr = 2002
*ptr = 'J'
In printf("%s\n", *ptr); the *ptr = 'J' and ASCII value of char 'J' is 74 but 74 address is not under your process control and you are trying to read from that memory location and its a memory violation and segmentation fault occurs.
If you compile you code containing printf("%s\n", *ptr); then with proper option say -Wall with GCC you will get a warning like below:
warning: format ‘%s’ expects argument of type ‘char *’, but argument 2 has type ‘int’
Says %s need (expects ) an address of type char* but you are putting value
notice:
printf("%s\n", *ptr);
^ ^ argument-2
argument-1
This is because the %s format specifier in the format string you pass to printf means that the corresponding argument should be a string, not a single character. And in C, a string is a pointer to the beginning of a block of characters that has a null character (byte with a value of 0) at the end.
Basically, this works because you're doing exactly what you're supposed to in order to print a string.
The %s formatter to printf expects a "string", which is really a pointer to a null-terminated array of characters.
That is to say, printf expects you to pass the pointer to it. When you dereference the pointer, it's taking the letter J, whose value in ascii is 74 (decimal), and tries treating that as a pointer to an array. That's an area of memory that's inaccessible, so you get the segmentation violation.
The format specifier %s tells printf to expect a pointer to a null-terminated char array. Which is what name and ptr are.
*name and *ptr are not. If you dereference them, you'll get back a single char, which is basically lying to printf - resulting in undefined behavior.
*ptr is essentially a reference to a single char, not to the string of char's. due to this char * and char[] are essentially the same thing
When you declare char prt = name thats where you are dereferencing it. the "" here isn't part of the variable just a way to show you want what that variable points to. If you were to put the *prt again in your printf you are doing it twice. name is an array of characters and *ptr is a dereferenced pointer to those characters.
Hope that explaination helps :-)

Can a pointer to a string be used in a printf?

I am thinking of something like:
#include <stdio.h>
#include <conio.h>
#include <stdlib.h>
int main(void) {
//test pointer to string
char s[50];
char *ptr=s;
printf("\nEnter string (s): ");
fgets(s, 50, stdin);
printf("S: %s\nPTR: %s\n", s, *ptr);
system("PAUSE");
return 0;
}
Or should I use a for loop with *(s+i) and the format specifier %c?
Is that the only possible way to print a string through a pointer and a simple printf?
Update: The printf operates with the adress of the first element of the array so when I use *ptr I actually operate with the first element and not it's adress. Thanks.
The "%s" format specifier for printf always expects a char* argument.
Given:
char s[] = "hello";
char *p = "world";
printf("%s, %s\n", s, p);
it looks like you're passing an array for the first %s and a pointer for the second, but in fact you're (correctly) passing pointers for both.
In C, any expression of array type is implicitly converted to a pointer to the array's first element unless it's in one of the following three contexts:
It's an argument to the unary "&" (address-of) operator
It's an argument to the unary "sizeof" operator
It's a string literal in an initializer used to initialize an array object.
(I think C++ has one or two other exceptions.)
The implementation of printf() sees the "%s", assumes that the corresponding argument is a pointer to char, and uses that pointer to traverse the string and print it.
Section 6 of the comp.lang.c FAQ has an excellent discussion of this.
printf("%s\n", ptr);
Is this what you want?
By the way, from printf(3), here's the documentation for the s conversion specifier (i.e %s):
If no l modifier is present: The const char * argument is expected to
be a pointer to an array of character type (pointer to a string).
Characters from the array are written up to (but not including) a
terminating null byte ('\0'); if a precision is specified, no more
than the number specified are written. If a precision is given, no
null byte need be present; if the precision is not specified, or is
greater than the size of the array, the array must contain a
terminating null byte.
you should do "printf("S: %s\nPTR: %s\n", s, ptr);
" instead of printf("S: %s\nPTR: %s\n", s, *ptr);
difference between ptr and *ptr is: ptr gives you the address in the memory of the variable you are pointing to and *ptr gives rather the value of the pointed variable In this case is *ptr = ptr[0]
this code will show what i mean:
printf("\tS: %s\n\tPTR: %s\n\tAddress of the pointed Value: %x\n\tValue of the whole String: %s\n\tValue of the first character of the String: %c\n", s, ptr,ptr,ptr,*ptr);
In my experience you should get segmentation fault when you try to use %s directive with *p.

Resources