why we need address operator to access two dimensional string elements - c

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.

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.

c function definition calls for pointer but example does not use pointers

I relatively new to low level programming such as c. I am reviewing the strstr() function here. When reviewing the function definition char *strstr(const char *str1, const char *str2); I understand that function will return a pointer or a NULL depending if str2 was found in str1.
What I can't understand though, is if the funciton requires the two inputs to be pointers, when does the example not use pointers?
#include <string.h>
int main ()
{
char string[55] ="This is a test string for testing";
char *p;
p = strstr (string,"test");
if(p)
{
printf("string found\n" );
printf ("First occurrence of string \"test\" in \"%s\" is"\
" \"%s\"",string, p);
}
else printf("string not found\n" );
return 0;
}
In strstr(string,"test");, string is an array of 55 char. What strstr needs here is a pointer to the first element of string, which we can write as &string[0]. However, as a convenience, C automatically converts string to a pointer to its first element. So the desired value is passed to strstr, and it is a pointer.
This automatic conversion happens whenever an array is used in an expression and is not the operand of sizeof, is not the operand of unary &, and is not a string literal used to initialize an array.
"test" is a string literal. It causes the creation of an array of char initialized with the characters in the string, followed by a terminating null character. The string literal in source code represents that array. Since it is an array used in an expression, it too is converted to a pointer to its first element. So, again, the desired pointer is passed to strstr.
You could instead write &"test"[0], but that would confuse people who are not used to it.

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 (*).

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

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.

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.

Resources