How to print array of string by taking of user input? I am confused between str+i
and str[i]
.
In my program, strings are not printed. It takes 5 strings as input, after that program terminates
#include <stdio.h>
int main()
{
char *str[5];
for (int i = 0; i < 5; i++)
{
scanf("%s", &str[i]);
}
for (int i = 0; i < 5; i++)
{
printf("%s\n", str[i]);
}
}
So firstly, go and read the answers, then come here for complete code. By span of 2 days, I arrived at two solutions to my problem with the help of below answers.
//1.
#include <stdio.h>
#include<stdlib.h>
int main()
{
char* str[5];
for (int i = 0; i < 5; i++)
{
str[i] = (char *)malloc(40 * sizeof(char));
scanf("%s", str[i]);
}
for (int i = 0; i < 5; i++)
{
printf("%s\n", str[i]);
}
}
//2
#include <stdio.h>
#include<stdlib.h>
int main()
{
char str[5][40];
for (int i = 0; i < 5; i++)
{
scanf("%s", &str[i]);
}
for (int i = 0; i < 5; i++)
{
printf("%s\n", str[i]);
}
}
Strings are a painful learning experience in c. Its quite unlike higher level languages.
First off, to answer your explicit question, str[i]
is the value of the i-th element in an array. If str
points to the array of characters"Hello"
, then str[1]
is the value "e". str + i
, on the other hand, is a pointer to the i-th element in an array. In the same situation, where str
points to the array of characters "Hello"
, str + 1
is a pointer to the "e" in that array. str[i]
and *(str + i)
are identical in every way. In fact, the spec defines a[b]
to be (*(a + b))
, with all of the behaviors that come with it! (As an aside, C still supports a very ancient notation i[str]
which is exactly the same as str[i]
because addition of pointers and integers is commutative. You should never use the backwards form, but its worth noting that when I say they are defined to be the same, I mean it!)
Note that I have been very careful to avoid the word "string," and focused on "character arrays" instead. C doesn't technically have a string type. This is important here because you can't do easy things like std::string str[5]
(which is a valid C++ notation to create an array of 5 strings) to get a variable length string. You have to make sure you have memory for it. char *str[5]
creates an array of 5 char*
, but doesn't create any arrays of characters to write to. This is why your code is failing. What is actually happening is each element of str
is a pointer to an unspecified address (garbage memory from whatever was there before the variable was created), and scanf
is trying to assign into that (nonexistent) array. Bad things happen when you write to somewhere random in memory!
There are two solutions to this. One is to use Serve Lauijssen's approach using malloc. Just please please please please please remember to use free()
to deallocate that memory. In nearly any real program, you will not want to leak memory, and using free
is a very important habit to get into early on. You should also make sure malloc
did not return null. That's another one of those habits. It virtually never returns null on a desktop, but it can. On embedded platforms, it can easily happen. Just check it! (And, from the fact that I have to be reminded of this in the comments suggests I failed to get in the habit early!)
The other approach is to create a multidimensional array of characters. You can use the syntax char str[5][80]
to create a 5x80 array of characters.
The exact behavior is a bit of a doozie, but you will find it just happens to behave the way you think it should in your case. You can just use the syntax above, and keep moving. However, you should eventually circle back to understand how this works and what is going on underneath.
C handles the access to these multidimensional arrays in a left to right manner, and it "flattens" the array. In the case of char str[5][80]
, this will create an array of 400 characters in memory. str[0]
will be a char [80]
(an 80 character array) which is the first 80 characters in that swath of memory. str[1]
will be the next swath of 80 characters, and so on. C will decay an array into a pointer implicitly, so when scanf
expects a char*
, it will automatically convert the char [80]
that is the value of str[i]
into a char*
that points at the first character of the array. phew
Now, all that explicit "here's what's actually going on" stuff aside, you'll find this does what you want. char str[5][80]
will allocate 400 characters of memory, laid out in 5 groups of 80. str[i]
will (almost) always turn into a char*
pointing at the start of the i-th group of characters. Then scanf
has a valid pointer to an array of characters to fill in. Because C "strings" are null-terminated, meaning they end at the first null (character 0
aka '\0'
) rather than at the end of the memory allocated for it, the extra unused space in the character array simply wont matter.
Again, sorry its so long. This is a source of confusion for basically every C programmer that ever graced the surface of this earth. I am yet to meet a C programmer who was not initially confused by pointers, much less how C handles arrays.
Three other details:
str
to strs
. It doesn't affect how the code runs, but if you are treating an object as an array, it tends to be more readable if you use plurals. If I was reading code, strs[i]
looks like the i-th string in strs
, while str[i]
looks like the i-th character in a string.scanf("%79s", str[i])
to make sure you don't read too many characters is highly highly highly desirable. Later on, you will be plagued by memory corruptions if you don't ingrain this habit early. The vast majority of exploits you read about in major systems are "buffer overruns" which are where an attacker gets to write too many characters into a buffer, and does something malicious with the extra data as it spills over into whatever happens to be next in the memory space. I'm quite sure you aren't worried about an attacker using your code maliciously at this point in your C career, but it will be a big deal later.char**
, that is a pointer to a pointer to a character. The multidimensional array approach won't actually work on that day. When I come across this, I have to create two arrays. The first is char buffer[400]
which is my "backing" buffer that holds the characters, and the second is char* strs[5]
, which holds my strings. Then I have to do strs[0] = buffer + (0 * 80); strs[1] = buffer + (1 * 80);
and so on. You don't need this here, but I have needed it in more advanced code.
static char backing[400]
. This creates a block of 400 bytes at compile time which can be used by the function. In general I'd recommend avoiding this, but I include it for completeness. There are some embedded software situations where you will want to use this due to platform limitations. However, this is terribly broken in multithreading situations, which is why many of the standard C functions that relied on static allocated memory now have a variant ending in _r
which is re-entrant and threadsafe.Since you have defined char *str[5]
, so str
should be of type char **
. So when scanf()
expects char *
, it is given &str[i]
which is of type char **
, and so it is not right. That is why your printf("%s\n", str[i])
might not work.
The (str+i)
(which is of type char **
and not the same as str[i]
) method might work with printf()
in the above case because you are reading string values to &str[i]
. This could be fine when you have input strings which are short. But then, reading values to &str[i]
is not what you intend here, because str[i]
is already of type char *
. Try giving a very very long string as input (like aaaaaaa...
) in the above code, and it will probably give you a Segmentation fault
. So technically the method is broken, and you really need to allocate memory to each char *
elements in your str
array before reading in strings. For example, you can do
for (int i=0; i<5; ++i)
str[i] = (char *) malloc(length_you_wish);
Since each str[i]
is of type char *
and scanf()
expects argument of type char *
, use scanf( "%s", str[i] )
, omitting &
before str[i]
.
Now, you can printf()
with
printf( "%s\n", str[i] )
or printf( "%s\n", *(str+i) )
, where str[i]
or *(str+i)
is of type char *
.
Lastly, you need to do
for (int i=0; i<5; ++i)
free(str[i])
Moral: str[i]
is a pointer to a specific char
array (it holds the address of the first char
element of the array), but (str+i)
points to str[i]
(it refers to the address of str[i]
, so (str+i)
and &str[i]
should have same value).
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With