Strings and character with printf - c

I was confused with usage of %c and %s in the following C program:
#include <stdio.h>
void main()
{
char name[] = "siva";
printf("%s\n", name);
printf("%c\n", *name);
}
Output:
siva
s
Why we need to use pointer to display a character %c, and pointer is not needed for a string
I am getting error when I run
printf("%c\n", name);
I got this error:
str.c: In function ‘main’:
str.c:9:2: warning: format ‘%c’ expects type ‘int’, but argument 2 has type ‘char *’

If you try this:
#include<stdio.h>
void main()
{
char name[]="siva";
printf("name = %p\n", name);
printf("&name[0] = %p\n", &name[0]);
printf("name printed as %%s is %s\n",name);
printf("*name = %c\n",*name);
printf("name[0] = %c\n", name[0]);
}
Output is:
name = 0xbff5391b
&name[0] = 0xbff5391b
name printed as %s is siva
*name = s
name[0] = s
So 'name' is actually a pointer to the array of characters in memory. If you try reading the first four bytes at 0xbff5391b, you will see 's', 'i', 'v' and 'a'
Location Data
========= ======
0xbff5391b 0x73 's' ---> name[0]
0xbff5391c 0x69 'i' ---> name[1]
0xbff5391d 0x76 'v' ---> name[2]
0xbff5391e 0x61 'a' ---> name[3]
0xbff5391f 0x00 '\0' ---> This is the NULL termination of the string
To print a character you need to pass the value of the character to printf. The value can be referenced as name[0] or *name (since for an array name = &name[0]).
To print a string you need to pass a pointer to the string to printf (in this case name or &name[0]).

%c
is designed for a single character a char, so it print only one element.Passing the char array as a pointer you are passing the address of the first element of the array(that is a single char) and then will be printed :
s
printf("%c\n",*name++);
will print
i
and so on ...
Pointer is not needed for the %s because it can work directly with String of characters.

You're confusing the dereference operator * with pointer type annotation *.
Basically, in C * means different things in different places:
In a type, * means a pointer. int is an integer type, int* is a pointer to integer type
As a prefix operator, * means 'dereference'. name is a pointer, *name is the result of dereferencing it (i.e. getting the value that the pointer points to)
Of course, as an infix operator, * means 'multiply'.

The name of an array is the address of its first element, so name is a pointer to memory containing the string "siva".
Also you don't need a pointer to display a character; you are just electing to use it directly from the array in this case. You could do this instead:
char c = *name;
printf("%c\n", c);

If you want to display a single character then you can also use name[0] instead of using pointer.
It will serve your purpose but if you want to display full string using %c, you can try this:
#include<stdio.h>
void main()
{
char name[]="siva";
int i;
for(i=0;i<4;i++)
{
printf("%c",*(name+i));
}
}

The thing is that the printf function needs a pointer as parameter. However a char is a variable that you have directly acces. A string is a pointer on the first char of the string, so you don't have to add the * because * is the identifier for the pointer of a variable.

Or you can use %c like in the below code:
#include <stdio.h>
void main()
{
char name[]="siva";
//prints as string form
printf("%s\n",name);
//print each letter on different line
int size= sizeof(name);
int i;
for(i=0;i<size;i++){
printf("%c\n",name[i]);
}
}

Related

String and pointer in C [duplicate]

This question already has answers here:
Strings and character with printf
(7 answers)
Closed 1 year ago.
Pointer are the variables which stores address.
char *ptr = "string";
printf("%s",ptr);
In this code snippet, the whole string was printing without dereferencing. Why was this happening?
And in this case the characters are printing it was working as expected just like an array.
char *ptr = "string";
printf("%c",*ptr);
What is the difference in these two cases
The format string "%s" expects that the corresponding argument points to the first character of a string and the function printf outputs the string until the terminating zero character '\0' is encountered.
In fact this call of printf
char *ptr = "string";
printf("%s",ptr);
is logically implemented under the hood the following way
#include <stdio.h>
int main(void)
{
char *ptr = "string";
for ( char *tmp = ptr; *tmp != '\0'; ++tmp )
{
printf( "%c", *tmp );
}
return 0;
}
The format string "%c" expect an object of the type char and the function printf outputs the object as a character.
The format string (%c or %s) tell it what to treat the parameters as.
The %s is for a string - so walks the pointer printing each character until it hits a \0.
The %c prints one character only.
You are defining a string literal, when you do char *ptr = "string";, which is a null-terminated sequence of characters.
The format argument %s prints a string until \0 is found, while %c prints a single character.
printf("%c", *ptr);
is slightly misleading. To make it clear you want one character out of the string...
printf("%c", ptr[0]);
So for the %c you dereference one char.
The %s dereferences the pointer, increasing it by a char until it reaches a \0.
The %s is equivalent to something like this, using %c:
void printf_s(char *cp) {
while(*cp)
printf("%c", *(cp++));
}
The expression *(cp++) says: cp[0], cp[1],...,cp[n].

C char pointer get a specific character

probably a dumb question but how do you access a specific character in a char pointer?
I've tried following...
char *pointer = "Hello";
printf("%s", pointer); // prints "Hello"
printf("%s", &pointer[0]); // also prints "Hello"
But what I want is printf(???) => "H". A single character. Or the "e". How is that possible?
pointer is a pointer to char, also called a char *.
After char *pointer = "Hello";, pointer points to the “H”.
When printf is given %s, it takes a char * and prints all the characters it finds starting at that location, until a null character is seen.
To tell printf to print a single character, pass it the actual character value (not a pointer) and use %c:
printf("%c", *pointer);
or:
printf("%c", pointer[0]);
or, for the “e” instead of the “H”:
printf("%c", pointer[1]);
char* pointer = "Hello";
Creates a pointer and assigns it to the base address of "Hello".
pointer and &pointer[0] are the same thing.
pointer[n] takes the address of "Hello" and offsets it by the number 'n', be sure not to index of the end of the address or you will read rubbish.
So:
pointer[0] = 'H'
pointer[1] = 'e'
pointer[2] = 'l'
pointer[3] = 'l'
pointer[4] = 'o'
pointer[5] = 0
You want to access the char of char* simply use [] operator, just like arrays.
char *pointer = "Hello";
printf("%s", pointer); // ok
printf("%s", &pointer[0]); // wrong way of accessing specific element (it is same as the base address.., thus %s prints the whole thing)
Instead you're accessing the address of the first element of char* or string literal.. why!
printf("%c", pointer[0]); // use this one
Just like arrays, access the required element.
However, to get it better, notice here:
#include <stdio.h>
int main() {
char *pointer = "Hello";
printf("%s\n\n", pointer); // ok
printf("%c", pointer[0]);
printf("%p == %p\n", (void *)&pointer[0],(void *)pointer);
// cast to void * to avoid undefined behavior
// pointed out by #ex nihilo
printf("%p", pointer+1);
return 0;
}
Output:
Hello
H0x55da21577004 == 0x55da21577004
0x55da21577005
as you can see, the pointer holds the address of the first element which is: &pointer[0] thus you get the same output.

Weird beahaviour of string pointers

#include <stdio.h>
int main()
{
char*m ;
m="srm";
printf("%d",*m);
return 0;
}
The output is 115. Can someone explain why it gives 115 as output?
*m is the same as m[0], i.e. the first element of the array pointed to by m which is the character 's'.
By using the %d format specifier, you're printing the given argument as an integer. The ASCII value of 's' is 115, which is why you get that value.
If you want to print the string, use the %s format specifier (which expects a char * argument) instead and pass the pointer m.
printf("%s\n", m);
You have a few problems here,
the first one is that you're trying to add three bytes to a char, a char is one byte.
the second problem is that char *m is a pointer to an address and is not a modifiable lvalue. The only time you should use pointers is when you are trying to point to data
example:
char byte = "A"; //WRONG
char byte = 0x61; //OK
char byte = 'A'; //OK
//notice that when setting char byte = "A" you will recieve an error,
//the double quotations is for character arrays where as single quotes,
// are used to identify a char
enter code here
char str[] = "ABCDEF";
char *m = str;
printf("%02x", *m); //you are pointing to str[0]
printf("%02x", *m[1]); //you are pointing to str[1]
printf("%02x", *m[1]); //you are pointing to str[1]
printf("%02x", *(m + 1)); //you are still pointing to str[1]
//m is a pointer to the address in memory calling it like
// *m[1] or *(m + 1) is saying address + one byte
//these examples are the same as calling (more or less)
printf("%02x", str[0]); or
printf("%02x", str[1]);
Pointers and arrays act similarly .Array names are also pointers pointing to the first element of the array.
You have stored "srm" as a character array with m pointing to the first element.
"%d" will give you the ASCII value of the item being pointed by the pointer.
ASCII value of "s" is 115.
if you increment your pointer (m++) then print it's ascii value , output will be ascii value of "r" - 114.
#include <stdio.h>
int main()
{
char *m ;
m="srm";
m++; //pointing to the 2nd element of the array
printf("%d",*m); //output = 114
return 0;
}

C - Error with mallocing a string

I keep getting the following errors when i try to compile my code below. I searched online for what the errors meant but nothing seemed to fit my code. Please could someone tell me where im going wrong in malllocing a string below. I want to make 5 units in that array, and this is the first one.
Errors:
assignment4.c: In function ‘readFile’:
assignment4.c:42:19: warning: assignment makes integer from pointer without a cast [enabled by default]
assignment4.c:44:2: warning: format ‘%s’ expects argument of type ‘char *’, but argument 2 has type ‘int’ [-Wformat]
Code:
void readFile()
{
char * listofdetails;
listofdetails = malloc(sizeof(char)*40);
listofdetails[1] = "cars";
printf("%s \n", listofdetails[1]);
free(listofdetails);
}
Use strcpy (don't forget to #include <string.h>):
strcpy(listofdetails, "cars");
Also, "%s", expects a string, not a char, if you want to print a string
printf("%s \n", listofdetails);
is what you want.
If you want to print the first character in the string:
printf("%c \n", listofdetails[0]);
But if you want a list of details (as the name suggests), you need to reserve space for the list of n string (char **), and for each string (char *):
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
extern char *strdup(const char *);
int main(void)
{
char **listofdetails = malloc(sizeof(*listofdetails) * 40);
if (listofdetails == NULL) {
perror("malloc");
exit(EXIT_FAILURE);
}
listofdetails[0] = strdup("cars");
if (listofdetails[0] == NULL) {
perror("strdup");
exit(EXIT_FAILURE);
}
printf("%s\n", listofdetails[0]);
free(listofdetails[0]);
free(listofdetails);
return 0;
}
Note that strdup is not part of the standard (but is available on many implementations).
Finally, if those strings are known at compile time you don't need to use malloc at all:
const char *listofdetails[] = {
"cars",
"trucks",
"motorcycles",
/* etc */
};
The two lines
char * listofdetails;
listofdetails = malloc(sizeof(char)*40);
can be written as
char * listofdetails = malloc(40);
(sizeof(char) is defined to be 1). Still you should not use magic numbers as 40 directly in the code but use aptly named constant
#define STRING_LENGTH 40
The line
listofdetails[1] = "cars";
is wrong, since the left side is the second character location in the list of details, and you try to assign a string character to it. Use
strcpy(listofdetails, "cars");
and the same problem in the line
printf("%s \n", listofdetails[1]);
Use
printf("%s \n", listofdetails);
instead.
listofdetails[1] is char(or int) type. %s expects a char * type. The fix:
printf("%s \n", listofdetails);
If you want to print out listofdetails[1], then use %c:
printf("%c \n", listofdetails[1]);
listofdetails[1] = "cars"; tries to assign a char array to a char(or int).
Instead, you can do:
listofdetails = malloc(sizeof(char)*40);
strcpy(listofdetails, "cars");
It would appear that you want a list of strings, but you're declaration of listofdetails is only a single string.
Instead, you need to add another pointer, like so:
char **listofdetails = malloc(sizeof(char *) * 40);
Now you can use listofdetails as you intend. Please note, however, that in C, array indexes start at 0, not 1. So you probably want to use listofdetails[0] = "cars"; to set the first element of your array.
You are assigning a string to a single byte location.
listofdetails[1] = "cars"; // Problem
where listofdetails[1] indicates a single character in a character array.
You should not assign string like above. use strcpy-
strcpy(listofdetails,"cars");
Else you can assign like this also
char *listofdetails = "cars";
It does not require memory allocation.
Try the below changes-
void readFile()
{
char * listofdetails;
listofdetails = malloc(sizeof(char)*40);
strcpy(listofdetails,"cars");
printf("%s \n", listofdetails);
free(listofdetails);
}
Use string.h and stdlib.h header file also.
a char is a single character (e.g. 'a')
char* is a pointer. in your case you allocate 40 (single) characters (malloc) and assign the address of the first to listofdetails. use strcpy, as Alter Mann wrote, to copy a string literal or any null-terminated sequence of chars to your listofdetails. to complete Alter Mann's example:
char * listofdetails;
listofdetails = malloc(sizeof(char)*40);
strcpy(listofdetails, "cars"); // make sure that the string on the right does not exceed 40 characters!
printf("%s\n", listofdetails); // will print "cars" on a single line
free(listofdetails);
example for array of strings:
char ** listofdetails;
listofdetails = malloc(sizeof(char*) * ARRAYSIZE);
listofdetails[0] = malloc(sizeof(char) * STRBUFFERSIZE);
strcpy(listofdetails[0], "cars");
printf("%s\n", listofdetails[0]);
free(listofdetails[0]); // delete string
free(listofdetails); // delete string-array
assignment4.c:42:19: warning: assignment makes integer from pointer without a cast [enabled by default]
comes from the line
listofdetails[1] = "cars";
listofdetails is an expression of type char *; listofdetails[1] is an expression of type char, which is an integral type, and it evaluates to the second element of the array that listofdetails points to. "cars" is an expression of type char * (more on that later), and you can't assign pointer values to integers without a cast.
This boils down to what listofdetails is supposed to store. Is it suposed to store a single string? If so, then you would need to write
strcpy( listofdetails, "cars" );
in order to copy the contents of the string literal "cars" to the memory listofdetails points to.
If it's supposed to store a pointer to an existing string or string literal, then you would skip the malloc step altogether and simply write
char *listofdetails = "cars";
The string literal "cars" is stored as a 5-element array of char such that it is allocated when the program starts up and released when the program exits. An array expression will be converted ("decay") to a pointer expression unless it is the operand of the unary & or sizeof operators, or is a string literal being used to initialize another array in a declaration.
In the case above, "cars" isn't the operand of the sizeof or unary & operators, and it isn't being used to initialize an array of char, so it decays to a char *, and its value is the address of the first character in the string. So by the time this is done, listofdetails points to the string literal "cars".
If it's supposed to store a list of pointers to strings, then you would need to do the following:
char **listofdetails = malloc( sizeof *listofdetails * 40 ); // note extra level of indirection
This will allocate enough memory to store 40 pointers to char; since the type of listofdetails is char **, the type of listofdetails[1] will be char *, so the following lines will work as you intend:
listofdetails[1] = "cars";
printf("%s \n", listofdetails[i] );
Making that last change will fix
assignment4.c:44:2: warning: format ‘%s’ expects argument of type ‘char *’, but argument 2 has type ‘int’ [-Wformat]
which is complaining about
printf("%s \n", listofdetails[1] );
since as currently written, listofdetails[1] has type char, which is promoted to int since printf is a variadic function, and %s expects the corresponding argument to have type char *.
One more thing; in C, arrays are 0-origin, so you'd use the index 0 to access the first element of the list, and index 39 to access the last one.

Why splitting the word in this way is crashing?

I executed the following code.
#include <stdio.h>
int main()
{char *a="awake";
printf("%s\n", *(a+1));
return 0; // expected out_put to be wake
}
You're dereferencing the pointer, which makes it a char but trying to output a string. Change your print statement to printf("%s\n", a+1);
*(a+1) is the same as a[1] which is a char, not the char * that printf expects for the %s.
EDIT: clarification: printf needs an address for the %s specifier, a+1 is such an address (namely the address of the second character in the string), but *(a+1) then gives the value at that address. Which is just a character and in all likelyhood not a valid memory location for printf to read.
You don't want to defrefeence the char *:
printf("%s\n", (a+1));
does what you want.

Resources