how to initialize and print a 2-d array of characters? - c

char name[5][5]={ "" };
printf("%s",&name[0][0]);
I just want to know why "&" is used in printf.
and why [][0] the second parenthesis has a '0' in it?
similarly
char *name[5][5]={ "" };
printf("%s",&name[0][0]);
why here also & is used?
I'm simply not able to understand .
in array of pointers shouldn't there be * instead of &?

%s expects an argument of type char *. &name[0][0] is of type char *. &name[0][0] is the address of the first character of first string. If you want to print the first string from the beginning, you have to use &name[0][0].
Using &name[0][1] will print the string from its second character, &name[0][2] from third character and so on provided the string is long enough.

Related

Why de-referencing is not used in case of printing of a string?

How we use a string name in C to print a string without dereferencing it?
Like here:
char str[];
printf("%s",str);
But in case of arrays we use dereferencing by square brackets[] to print an array:
int a[10];
for(i=0;i<10;i++);
printf("%d",a[i]);
What's the difference between printing a string and an array? We need dereferencing an array by using square brackets [] but in case of string without using any dereferencing printf(); is just printing the value of the string and not the address.
Because that is what the interface to printf dictates.
In case of a "%s" it expects a pointer to a NUL terminated string.
In case of a "%d" it expects an int.
It all depends on what the function (printf or else) expects.
When you use printf with %s, like
printf("%s",str);
printf() wants "a string" which, in C, is the same as "an array of [NUL-terminated] char". So, you pass the only thing that identifies actually the whole array: its name (which decays to the address of the first element).
The same applies to every function that expects an array as argument.
If, to the function you call, you must pass something else, you use different approaches. When printf is used to print an integer, like
printf("%d",a[i]);
you must pass an integer; and an array is not an integer, so you must dereference (or "select") an integer from the array, using the correct notation/mechanism. But things are not different if you want to use a member of a struct, for example. You can not pass printf() a struct, so you use the dot to select a [correct] member of the struct. And the same applies to pointers to integer, you dereference them when you want the value and not the pointer itself. And so on for functions... like
printf("%d", (int) floor(PI));
In the above line, again, if printf wants an integer, you must give it an integer, so to use PI (3.14) you must convert it to an int.
For starters for example such a code snippet
char str[5] = "Hello";
printf("%s",str);
can result in undefined behavior.
The format string "%s" expects that the argument is a pointer to first character of a string.
In C the string is defined as a sequence of characters terminated by the zero character '\0'. That is a character array that contains a string has the sentinel value '\0'.
So in fact such a call of printf
printf("%s",str);
logically is similar to the following code
while ( *str != '\0' ) putchar( *str++ );
In the example above
char str[5] = "Hello";
the character array str does not contain a string because its five elements were initialized by characters of the string literal "Hello" excluding its terminating zero character (there is no enough space in the array to accommodate the sixth character '\0' of the string literal).
So such a call
printf("%s",str);
for the array declared above will try to output anything that follows the array in the memory.
To avoid the undefined behavior you should declare the array for example like
char str[6] = "Hello";
or like
char str[] = "Hello";
As for arrays of other fundamental types then in most cases they do not have a standard sentinel value. Opposite to strings it is impossible to define such a sentinel value for example for integer or float arrays.
So character arrays that contains strings are exclusions from the total kinds of arrays. Strings always end with the terminating zero character '\0' by the definition of the string in C. That is not valid for other kinds of arrays.
Hence to output any array of other kinds you in general need to use a loop knowing how many elements you need to output.

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

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.

Use of pointers to store character strings

I started learning pointers in C. I understood it fine untill I came across the topic "Using Pointers to store character arrays".
A sample program to highlight my doubt is as follows
#include <stdio.h>
main()
{
char *string;
string = "good";
printf ("%s", string);
}
This prints the character string, i.e, good.
Pointers are supposed to store memory addresses, or in other words, we assign the adress of a variable (using the address operator) to a pointer variable.
What I don't understand is how are we able to assign a character string directly to the pointer? That too without address operator?
Also, how are we able to print the string without the indirection operator (*) ?
A literal string like "good" is really stored as a (read-only) array of characters. Also, all strings in C must be terminated with a special "null" character '\0'.
When you do the assingment
string = "good";
what is really happening is that you make string point to the first character in that array.
Functions handling strings knows how to deal with pointers like that, and know how to loop over such arrays using the pointer to find all the characters in the string until it finds the terminator.
Looking at it a little differently, the compile creates its array
char internal_array[] = { 'g', 'o', 'o', 'd', '\0' };
then you make string point to the first element in the array
string = &internal_array[0];
Note that &internal_array[0] is actually equal to internal_array, since arrays naturally decays to pointers to their first element.
"cccccc" is a string literal which is actually the char array stored in the ReadOnly memory. You assign the pointer to the address of the first character of this literal.
if you want to copy string literal to the RAM you need to:
char string[] = "fgdfdfgdfgf";
Bare in mind that the array initialization (when you declare it) is the only place where you can use the = to copy the string literal to the char array (string).
In any other circumstances you need to use the appropriate library function for example.
strcpy(string, "asdf");
(the string has to have enough space to accommodate the new string)
What I don't understand is how are we able to assign a character string directly to the pointer? That too without address operator?
When an array is assigned to something, the array is converted to a pointer.
"good" is a string literal. It has a array 5 of char which includes a trailing null character. It exists in memory where write attempts should not be attempted. Attempting to write is undefined behavior (UB). It might "work", it might not. Code may die, etc.
char *string; declare string as pointer to char.
string = "good"; causes an assignment. The operation takes "good" and converts that array to the address and type (char*) of its first element 'g'. Then assigns that char * to string.
Also, how are we able to print the string without the indirection operator (*) ?
printf() expects a char * - which matches the type of string.
printf ("%s", string); passes string to printf() as a char * - no conversion is made. printf ("%s",... expects to see a "... the argument shall be a pointer to the initial element of an array of character type." then "Characters from the array are written up to (but not including) the terminating null character." C11 ยง7.21.6.1 8.
Your first question:
What I don't understand is how are we able to assign a character string directly to the pointer? That too without address operator?
A character string literal is a sequence of zero or more multibyte characters enclosed in double-quotes, for e.g. "good".
From C Standard#6.4.5 [String literals]:
...The multibyte character sequence is then used to initialize an array of static storage duration and length just sufficient to contain the sequence. For character string literals, the array elements have type char, and are initialized with the individual bytes of the multibyte character sequence.....
In C, an expression that has type array of type is converted to an expression with type pointer to type that points to the initial element of the array object [there are few exceptions]. Hence, the string literal which is an array decays into pointer which can be assigned to the type char *.
In the statement:
string = "good";
string will point to the initial character in the array where "good" is stored.
Your second question:
Also, how are we able to print the string without the indirection operator (*) ?
From printf():
s
writes a character string
The argument must be a pointer to the initial element of an array of characters...
So, format specifier %s expect pointer to initial element which is what the variable string is - a pointer to initial character of "good". Hence, you don't need indirection operator (*).

Print an element of 2D array of character or string?

main()
{
char str[][3]={"ab","cd","ef","gh"};
printf("\n%s\n%s",str[2][0],&str[0][0]);
//WHY WE NEED TO PUT "&" TO PRINT &str[2][0] the element.
}
//while this works properly
main()
{
char str[][3]={"ab","cd","ef","gh"};
printf("\n%s\n%s",str[2],&str[0]);
}
str[2] is the third element of array str. It is in turn a character array that has type char[3]. In function call like this
printf( "%s", str[2] );
the array is converted to pointer to its first character (element). The first character of array str[2] can be gotten like str[2][0]. So its address is determined like &str[2][0].
Thus expressions str[2] and &str[2][0] are equivalent.
As for this call
printf("\n%s\n%s",str[2],&str[0]);
then it is invalid. Format specifier %s expects an argument of type char * while the type of expression &str[0] is char **. However because in any case expression &str[0] has the value that is the address of the first element of array str[0] the function produces the correct result.
If you want to ouput only a single character instead of a string you have to use format specifier %c For example
printf("\n%c\n%s",str[2][0],&str[0][0]);
^^^
In this function call as str[2][0] is a single character then there is used format specifier %c for its output.

why we need address operator to access two dimensional string elements

why we need address operator to access two dimensional string elements whereas in case of simple array we need not.we just use subscript notation in case of simple array
for ex
char masterlist[6][10] = {
"akshay",
"parag",
"raman",
"srinivas",
"gopal",
"rajesh"
};
printf("\nOriginal: %s %s", &names[2][0], &names[3][0] ) ;
whereas in case of array we just use
printf("%d",a[2][3]);
where a is an integer array.
The reason is simply because, when printf is invoked with %s as format specifier, it expects an argument of type char *, and not char which you would expect if you compare it to %d.
Format specifier %s is used to output strings - that is, sequences of characters - terminated with the null character '\0'.
If you have a two dimensional array with elements of type char, as in your example, then you can use the subscript operator:
char masterlist[6][10] = {
"akshay",
"parag",
"raman",
"srinivas",
"gopal",
"rajesh"
};
printf("\nOriginal: %s %s", names[2], names[3] ) ;
Both names[2] and names[3] have type char [10] and represent character strings.
If you want to compare with an integer array when the following statement is used:
printf("%d",a[2][3]);
Then it outputs an element of the array. You could write the same way for the original character array:
printf("%c", names[2][3] ) ;
This statement would output character 'a' (if I am not mistaken).
If you want to output an entire character string instead of a single element of the array you have to use code I showed above.
Consider a simplified example. Let's assume there is a function
void f( const char s[10] );
This function declaration is equivalent to
void f( const char *s );
and the both declare the same one function.
That is an array passed as an argument to the function will be adjusted to a pointer to its first element. If you have an array
char s[10] = "Hello";
then these expressions are equivalent
f( s );
f( &s[0] );
The both pass a pointer to the first element of the array.
In the second printf, you print a single int. In the first printf, you print a string, i.e. char array.
Because names[2][0] does not represent a string, it is a character from that string (in this case, the char p). &names[2][0] means "give me the address of the first character in that string", ie. the beginning of the string.
The language expects a pointer to a char as a string.
This is the way to print a string. In your 2-dimensional array you store strings. Even in the simple case where you had a string like char *string="Hello"; you would print it like this:
printf("%s", string); where string is a pointer. So when you want to print a string from an array you need to get the address of its first element.
To print out an array of characters (a string) you need to provide the function with the first value of the array (index 0).
Therefore you are saying &names[3][0], which basically returns the first element of the 4th array in the array names.
It's also equivalent to names[3] as they both point to the same place in the memory.

Resources