When printf a string we are not using *. Why? - c

In c programming when we print a string. We are not using * . But when print a number using printf we are using *. So how it is understanding, i am printing a string or int. Is understanding using %s operator?
Attaching an example code
#include<stdio.h>
int main(int argc,char* argv){
char data[]="This is an example of pointer";
char *pointerstringdata =data;
printf("print the string data is >> %s\n",pointerstringdata); /* Here we are not using * why? case -1*/
int numberdata =100;
int *pointerintdata=&numberdata;
printf("print the int data is >> %d\n",*pointerintdata); /* Here we are using * why? case -2*/
return 0;
}

when we print a string. We are not using * . But when print a number using printf we are using *
Because the d conversion specifier expects an int, whereas the s conversion specifier expects a pointer (to a char and with this to the 1st element of a 0-terminated char array, which in fact is what C uses to mimik what commonly is called a "string").

The C language has no provision for treating a string as a value. You cannot pass a string to function. The pointer pointerstringdata is just a pointer to a char, so *pointerstringdata is one char, not a string. Passing *pointerstringdata will pass only one character, not a string.
To print strings, when %s is used, printf expects the argument to be a pointer. It uses this pointer to read from memory, and it reads and prints characters until it finds null characters.
In contrast, C does support treating numbers as values, so they can be passed to functions directly.

The %s format specifier is expecting a pointer.
If you pass *pointerstringdata the function will receive the first character in the array, which the function will try to dereference, and probably cause a crash.

in
char data[]="This is an example of pointer";
char *pointerstringdata =data;
printf("print the string data is >> %s\n",pointerstringdata); /* Here we are not using * why? case -1*/
if you want to print all the string you have to give its address, no *
if you want to print its first character you do `printf("%c", *pointerstringdata);
in
int numberdata =100;
int *pointerintdata=&numberdata;
printf("print the int data is >> %d\n",*pointerintdata); /* Here we are using * why? case -2*/
you do not want to print the address memorized in pointerintdata but the value same in that address, so you have to dereference
there is no difference with a string ... except that you want to write all the string
a pointer is a pointer, whatever it is a pointer to a char or a pointer to an int

Disclaimer: This is an explanation about how it appear to the developer, this is not how it is after compiling the code (especially because the optimizer might change it all).
C is a very low level language. You need to understand that a variable always contains a value of a few bytes.
C is also one of the languages that made it very convenient to access larger structures.
The content of the variable can be:
A value (e.g: as you mentioned a number)
A address in the RAM
A structure that uses more consecutive ram (and C makes it nice to use it as if it was more than that)
stuct (fixed length)
array with fixed length
There is no real concept of having a dynamic length variable as a value, therefor strings as well as arrays of dynamic length only have the address in the variable.
As stings are variable length, the convention in C is:
Have an address in the variable
Read the real data byte by byte starting at that address
Read data until the byte is 0 (NULL)
That is called a null-terminated string.
This way you can pass data of variable length to printf, and printf will find out the length by looking for the first byte that is 0.
Converting variables containing address to those containing value works like this:
var_with_value = *var_with_address
var_with_address = &var_with_value
"var_with_address" is called a pointer.
In conclusion: You need to pass strings as address not as value, and numbers as value not as address, and that is the difference why you have to use *

Because pointers hold reference to the object. * dereference this object. So if the pointer holds the reference to the char object when we dereference it we get this object. So dereference char pointer is just the single char not the address of the first char in the string.

Related

char * vs char[] and much more

I'm confused about the way C handles strings and char * vs char[].
char name[10] = "asd";
printf("%p\n%p", &name, &name[0]); //0x7ffed617acd
//0x7ffed617acd
If this code gives the same addresses for both arguments, does it mean that the C compiler takes char arrays (strings) as a pointer to the first char in the array and moves in the memory till it gets the null terminator? Why wouldn't the same happen if we changed the char name[] to char *name? (I know they differ but what makes C take both in a different way?)
I know that arrays can't be assigned after declaration (unless you used something like strcpy, strcat) which is also confusing. Why wouldn't C take them as any other data type? (Something tells me the compiler has a specific addr for it while you can assign char* to whatever location in the mem since its a pointer).
I know that char * have fixed size unlike char[] which makes char * not usable for first argument of strcat.
in C a "string" is an array of type "char" (terminated with \0).
When you are referring to an array in C, you are using a pointer to the first element. In this case (char *).
According to the ANSI-C standard the name of an array is a pointer to the first element.
Being able to write name instead of &name[0] is syntactical sugar.
In the same way accessing an array element writing name[i] is analogue to writing *(name+i).
does it mean that the c compiler takes char arrays (strings) as a pointer to the first char in the array
An array is not a pointer. But an array will implicitly convert to a pointer to first element. Such conversion is called "decaying".
... and moves in the memory till it gets the null terminator???
You can write such loop if you know the pointer is to an element of null terminated string. If you write that loop, then the compiler will produce a program that does such thing.
Why wouldn't the same happen if we changed the char name[] to char *name?
Your premise is faulty. You can iterate an array directly, as well as using a pointer.
If this code gives the same addresses for both arguments, does it mean
The address of an object is the first byte of the object. What this "same address" means is that the first byte of the first element of the array is in the same address as the first byte of the array as a whole.
I know that arrays can't be assigned after declaration (unless you used something like strcpy, strcat) which is also confusing.
Neither strcpy nor strcat assign an array. They assign elements of the array which you can also do without calling those functions.
Why wouldn't C take them as any other data type?
This question is unclear. What do you mean by "C taking them"? Why do you think C should take another data type? Which data type do you think it should take?
char name[10] = "asd";
printf("%p\n%p", &name, &name[0]);
The arguments are of type char(*)[10] and char* respectively. The %p format specifier requires that the argument is of type similar to void* which isn't similar to those arguments. Passing an argument of a type other than required by the format specifier results in undefined behaviour. You should cast other pointer types to void* when using %p.

Why the char has to be a pointer instead of a type of char?

#include <stdio.h>
typedef struct {
char * name;
int age;
} person;
int main() {
person john;
/* testing code */
john.name = "John";
john.age = 27;
printf("%s is %d years old.", john.name, john.age);
}
This a well-working code, I just got a small question.
In the struct part, after I delete the * before name, this code no longer works, but no matter the age's type is, int or a pointer, it always works fine. So can anyone tell me why name has to be a pointer rather than just a type of char?
char type is short for character and can hold one character. C has no string type, instead a string in C is an array of char terminated with '\0' - the null character (null terminated strings).
Thus to use a string you need a pointer to memory that contains lots of characters. So why does it work for an int with or without the *. Well we can either have the age as an int or we can have a pointer to memory that stores the age. Either works well. But we can't store a string in one character.
This has to do with format specifiers you've in printf function. %s tries to output the string (reads a portion of memory), %d interprets everything in gets like an integer, thus even a pointer sort of works, however, you shouldn't to that, it's undefined behavior.
I suggest you to read some good books on C to get a good grasp on such things, a good list is here The Definitive C Book Guide and List
but no matter the age's type is int or a pointer, it always works fine.
That's undefined behaviour.
To elaborate, a double-quote delimited string (as seen above) is a string literal, and when used as an initializer, it basically gives you a pointer to the starting of the literal thereby it needs a pointer variable to be stored. So, name has to be a pointer.
OTOH, the initializer 27 is an integer literal (integer constant) and it needs to be stored into an int variable , not an int *. If you use 27 to initialize an int * and use that, it works (rather, seem to work) because that way, it invokes undefined behavior later, by attempting to use invalid memory location.
FWIW, if you try something like
typedef struct {
char * name;
int *age;
} person;
and then
john.age = 27; //incompatible assigment
compiler will warn you about wrong conversion from integer to pointer.
char *name: name is a pointer to type char. Now, when you make it to point to "John", the compiler stores the John\0 i.e., 5 chars to some memory and returns you the starting address of that memory. So, when you try to read using %s (string format specifier), the name variable returns you the whole string reading till \0.
char name : Here name is just one char having 1 byte of memory. So, you can't store anything more than one char. Also, when you would try to read, you should always read just one char (%c) because trying to read more than that will take you to the memory region which is not assigned to you and hence, will invoke Undefined Behavior.
int age : age is allocated 4 bytes, so you can store an integer to this memory and read as well, printf("%d", age);
int *age : age is a pointer to type int and it stores the address of some memory. Unlike strings, you do not read integers using address (loosely saying, just for the sake of avoiding complexity). You have to dereference it. So first, you need to allocate some memory, store any integer into it and return the address of this memory to age. Or else, if you don't want to allocate memory, you can use compiler's help by assigning a value to age like this, *age = 27. In this case, compiler will store 27 to some random memory and will return the address to age which can be dereferenced using *age, like printf("%d", *age);

About pointers and strcpy() in C

I am practicing allocation memory using malloc() with pointers, but 1 observation about pointers is that, why can strcpy() accept str variable without *:
char *str;
str = (char *) malloc(15);
strcpy(str, "Hello");
printf("String = %s, Address = %u\n", str, str);
But with integers, we need * to give str a value.
int *str;
str = (int *) malloc(15);
*str = 10;
printf("Int = %d, Address = %u\n", *str, str);
it really confuses me why strcpy() accepts str, because in my own understanding, "Hello" will be passed to the memory location of str that will cause some errors.
In C, a string is (by definition) an array of characters. However (whether we realize it all the time or not) we almost always end up accessing arrays using pointers. So, although C does not have a true "string" type, for most practical purposes, the type pointer-to-char (i.e. char *) serves this purpose. Almost any function that accepts or returns a string will actually use a char *. That's why strlen() and strcpy() accept char *. That's why printf %s expects a char *. In all of these cases, what these functions need is a pointer to the first character of the string. (They then read the rest of the string sequentially, stopping when they find the terminating '\0' character.)
In these cases, you don't use an explicit * character. * would extract just the character pointed to (that is, the first character of the string), but you don't want to extract the first character, you want to hand the whole string (that is, a pointer to the whole string) to strcpy so it can do its job.
In your second example, you weren't working with a string at all. (The fact that you used a variable named str confused me for a moment.) You have a pointer to some ints, and you're working with the first int pointed to. Since you're directly accessing one of the things pointed to, that's why you do need the explicit * character.
The * is called indirection or dereference operator.
In your second code,
*str = 10;
assigns the value 10 to the memory address pointed by str. This is one value (i.e., a single variable).
OTOTH, strcpy() copies the whole string all at a time. It accepts two char * parameters, so you don't need the * to dereference to get the value while passing arguments.
You can use the dereference operator, without strcpy(), copying element by element, like
char *str;
str = (char *) malloc(15); //success check TODO
int len = strlen("Hello"); //need string.h header
for (i = 0; i < len; i ++)
*(str+i)= "Hello"[i]; // the * form. as you wanted
str[i] = 0; //null termination
Many string manipulation functions, including strcpy, by convention and design, accept the pointer to the first character of the array, not the pointer to the whole array, even though their values are the same.
This is because their types are different; e.g. a pointer to char[10] has a different type from that of a pointer to char[15], and passing around the pointer to the whole array would be impossible or very clumsy because of this, unless you cast them everywhere or make different functions for different lengths.
For this reason, they have established a convention of passing around a string with the pointer to its first character, not to the whole array, possibly with its length when necessary. Many functions that operate on an array, such as memset, work the same way.
Well, here's what happens in the first snippet :
You are first dynamically allocating 15 bytes of memory, storing this address to the char pointer, which is pointer to a 1-byte sequence of data (a string).
Then you call strcpy(), which iterates over the string and copy characters, byte per byte, into the newly allocated memory space. Each character is a number based on the ASCII table, eg. character a = 97 (take a look at man ascii).
Then you pass this address to printf() which reads from the string, byte per byte, then flush it to your terminal.
In the second snippet, the process is the same, you are still allocating 15 bytes, storing the address in an int * pointer. An int is a 4 byte data type.
When you do *str = 10, you are dereferencing the pointer to store the value 10 at the address pointed by str. Remind what I wrote ahead, you could have done *str = 'a', and this index 0 integer would had the value 97, even if you try to read it as an int. you can event print it if you would.
So why strcpy() can take a int * as parameter? Because it's a memory space where it can write, byte per byte. You can store "Hell" in an int, then "o!" in the next one.
It's just all about usage easiness.
See there is a difference between = operator and the function strcpy.
* is deference operator. When you say *str, it means value at the memory location pointed by str.
Also as a good practice, use this
str = (char *) malloc( sizeof(char)*15 )
It is because the size of a data type might be different on different platforms. Hence use sizeof function to determine its actual size at the run time.

Store integer values as a string in C

Following code print integer values:
for ( i=0 ; i<COL ; i++ )
{
fprintf(iOutFile,"%02x ",(int)(iPtr[offset]));
}
I want to store these integer values as a string in a character pointer. To do so, I tried following code but it does not work.
char *hexVal="";
char *temp;
int val;
for ( i=0 ; i<COL ; i++ )
{
fprintf(iOutFile,"%02x ",(int)(iPtr[offset]));
val = (int)(iPtr[offset]);
temp=(char*) val;
hexVal = strcat(hexVal,temp);
}
printf("%s", hexVal);
Thanx.......
When you write
char* hexVal = "";
you are setting hexVal to point to a string literal, later in your code you try to strcat to that address which will cause undefined behavior.
What you need to do is to allocate a large enough area to hold your resulting string and then let hexVal point to that.
E.g.
char* hexVal = malloc(100); // or how much bytes you need
then just do
strcat(hexVal, temp);
alt. allocate on stack
char hexVal[100];
You are approaching this wrong. In general, if you have an int i then you can't just typecast a char *cp to the address (or the value) of i and expect it to magically become a string that you can printf or use in strcat. For one thing, strings are null-terminated and don't have a fixed length, while ints have a fixed size of typically 32 bits long.
You have to create a separate buffer (memory space) where snprintf will happily create a string-representation of your int value for you.
I think that your question is more about understanding how programming, pointers and C work in general, than about ints and strings and their conversion.
You are getting undefined behavior since there is no writable memory at hexVal, which just points at a read-only area containing a character with the value 0. It is a valid string, but it's constant and has length 0, you cannot append to it.
Also, of course you can't cast an integer into a "string", that's just not how C works. This:
temp=(char*) val;
simply re-interprets the value of val as a pointer (i.e. as an address), it doesn't magically compute the proper sequence of digit characters used to represent the address, i.e. it doesn't convert val to a string.
You can use snprintf() to convert an integer to a string.
So, to summarize:
Change hexval's declaration into e.g. char hexval[32] = "";, this declares it as an array of 32 characters, giving you plenty of space into which to build a number as a string. It also initializes the array so the first character is 0, thus making it into an empty string (with space to grow).
Use e.g. snprintf(tmp, sizeof tmp, "%d", 4711); to format a number into a string (which should be e.g. char tmp[16];) in decimal form.
Use strcat(hexval, tmp); to concatenate the newly built numeric string onto hexval.
BEWARE that you can't concatenate forever, you will run out of space if you do it too long. Adjust the sizes, in that case.
Check return values where possible, read the manual pages (Google man FUNCTION where FUNCTION is a standard C library function like strcat).

pointer of char and int

Hi I have a simple question
char *a="abc";
printf("%s\n",a);
int *b;
b=1;
printf("%d\n",b);
Why the first one works but the second one doesnot work?
I think the first one should be
char *a="abc";
printf("%s\n",*a);
I think a stores the address of "abc". So why it shows abc when i print a? I think I should print *a to get the value of it.
Thanks
Ying
Why the first one works but the second one doesnot work?
Because in the first, you're not asking it to print a character, you're asking it to print a null-terminated array of characters as a string.
The confusion here is that you're thinking of strings as a "native type" in the same way as integers and characters. C doesn't work that way; a string is just a pointer to a bunch of characters ending with a null byte.
If you really want to think of strings as a native type (keeping in mind that they really aren't), think of it this way: the type of a string is char *, not char. So, printf("%s\n", a); works because you're passing a char * to match with a format specifier indicating char *. To get the equivalent problems as with the second example, you'd need to pass a pointer to a string—that is, a char **.
Alternatively, the equivalent of %d is not %s, but %c, which prints a single character. To use it, you do have to pass it a character. printf("%c\n", a) will have the same problem as printf("%d\n", b).
From your comment:
I think a stores the address of "abc". So why it shows abc when i print a? I think I should print *a to get the value of it.
This is where the loose thinking of strings as native objects falls down.
When you write this:
char *a = "abc";
What happens is that the compiler stores a array of four characters—'a', 'b', 'c', and '\0'—somewhere, and a points at the first one, the a. As long as you remember that "abc" is really an array of four separate characters, it makes sense to think of a as a pointer to that thing (at least if you understand how arrays and pointer arithmetic work in C). But if you forget that, if you think a is pointing at a single address that holds a single object "abc", it will confuse you.
Quoting from the GNU printf man page (because the C standard isn't linkable):
d, i
The int argument is converted to signed decimal notation …
c
… the int argument is converted to an unsigned char, and the resulting character is written…
s
… 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') …
One last thing:
You may be wondering how printf("%s", a) or strchr(a, 'b') or any other function can print or search the string when there is no such value as "the string".
They're using a convention: they take a pointer to a character, and print or search every character from there up to the first null. For example, you could write a print_string function like this:
void print_string(char *string) {
while (*string) {
printf("%c", *string);
++string;
}
}
Or:
void print_string(char *string) {
for (int i=0; string[i]; ++i) {
printf("%c", string[i]);
}
}
Either way, you're assuming the char * is a pointer to the start of an array of characters, instead of just to a single character, and printing each character in the array until you hit a null character. That's the "null-terminated string" convention that's baked into functions like printf, strstr, etc. throughout the standard library.
Strings aren't really "first-class citizens" in C. In reality, they're just implemented as null-terminated arrays of characters, with some syntactic sugar thrown in to make programmers' lives easier. That means when passing strings around, you'll mostly be doing it via char * variables - that is, pointers to null-terminated arrays of char.
This practice holds for calling printf, too. The %s format is matched with a char * parameter to print the string - just as you've seen. You could use *a, but you'd want to match that with a %c or an integer format to print just the single character pointed to.
Your second example is wrong for a couple of reasons. First, it's not legal to make the assignment b = 1 without an explicit cast in C - you'd need b = (int *)1. Second, you're trying to print out a pointer, but you're using %d as a format string. That's wrong too - you should use %p like this: printf("%p\n", (void *)b);.
What it really looks like you're trying to do in the second example is:
int b = 1;
int *p = &b;
printf("%d\n", *p);
That is, make a pointer to an integer, then dereference it and print it out.
Editorial note: You should get a good beginner C book (search around here and I'm sure you'll find suggestions) and work through it.

Resources