1

I am stumped on how to store strings in an array in C, with each character kept separately. As an example, if the user inputs hellop, I want to store it in a given array, say userText, with userText[0] = h, userText[1] = e, userText[2] = l, and so on. I know this is easy stuff, but I'm still new. So if anyone could help, it would be great. Please explain how to do this using pointers.

#include<stdio.h>
void main()
{
    char a[10],c;
    int i=0;
    while((c=getchar())!='\n')
    {
        scanf("%c",&a[i++]);
        c=getchar();
     }
     for(i=0;i<11;i++)
         printf("%c",a[i]);
}

The program outputs some garbage value (eoeoeoeo\363) when I type in hellop.

svlasov
  • 9,923
  • 2
  • 38
  • 39
user2316393
  • 89
  • 2
  • 2
  • 6
  • 1
    `char buffer[20]; fgets(buffer, 20, stdin); buffer[strlen(buffer) -1] = '\0';` - this declares an array to store the input, gets the input using `fgets` and then gets rid of the newline using `strlen`. You'll need `#include ` and `#include ` for this. – Nobilis Jul 06 '13 at 15:03
  • 1
    @Nobilis Please post that as an answer, not a comment. – John Kugelman Jul 06 '13 at 15:09
  • @Devolus I edited it and added my code. – user2316393 Jul 06 '13 at 15:12
  • @JohnKugelman Done :) Just didn't feel it was really worthy of a whole answer but I've expanded it a bit and hopefully OP will give the links in it a thorough read. – Nobilis Jul 06 '13 at 15:19
  • What is wrong with the way I'm doing it? – user2316393 Jul 06 '13 at 15:21
  • It is discarded input character so read twice in getchar and scanf. and also Can not be safely read a string that does not know the length – BLUEPIXY Jul 06 '13 at 15:35

3 Answers3

10

To read input I recommend using the fgets function. It's a nice, safe alternative to scanf.

First let's declare a buffer like so:

char user_input[20];

Then we can get user input from the command line in the following manner:

fgets(user_input, 20, stdin);

This will store a maximum of 20 characters into the string from the standard input and it will ensure it is null-terminated. The fact that we've limited the input to the size of the array declared earlier ensures that there's no possibility of buffer overruns.

Then let's clear the pesky newline that's been entered into the string using strlen:

user_input[strlen(user_input) -1] = '\0';

As strlen returns the size of the string up to the null terminator but without it, we can be sure at that position lies the newline character (\n). We replace it with a null-terminator(\0) so that the string ends there.

Finally, let's print it using printf:

printf("The user has entered '%s'\n", user_input);

To use fgets and printf you will need to declare the following header:

#include <stdio.h>

For strlen we need another header, namely:

#include <string.h>

Job done.

P.S. If I may address the code you've added to your question.

  1. main is normally declared as int main rather than void main which also requires that main returns a value of some sort. For small apps normally return 0; is put just before the closing brace. This return is used to indicate to the OS if the program executed successfully (0 means everything was OK, non-zero means there was a problem).

  2. You are not null-terminating your string which means that if you were to read in any other way other than with a careful loop, you will have problems.

  3. You take input from the user twice - once with getchar and then with scanf.

If you insist on using your code I've modified it a bit:

#include<stdio.h>
int main()
{
    char a[10];
    int i=0;
    while( (a[i++]=getchar()) != '\n' && i < 10) /* take input from user until it's a newline or equal to 10 */
        ;
     a[i] = '\0'; /* null-terminate the string */
     i = 0;  
     while(a[i] != '\0') /* print until we've hit \0 */
         printf("%c",a[i++]);

     return 0;
}

It should now work.

Nobilis
  • 7,310
  • 1
  • 33
  • 67
  • What is wrong with the way I'm doing it? – user2316393 Jul 06 '13 at 15:21
  • @user2316393 Sorry I hadn't noticed you had updated your answer. Well, as I've pointed out `scanf` is a [dangerous function](http://stackoverflow.com/questions/2430303/disadvantages-of-scanf). Also my way does not rely on loops reducing code, possibilities for something to go wrong (i.e. bugs) and clutter :) With regards to your pointers request, when passing `user_input` to `fgets` it will decay into a pointer as arrays always decay into pointers when passed as function arguments. The same applies for `printf` and `strlen`. Not sure if this is what you are interested in. – Nobilis Jul 06 '13 at 15:23
  • Yeah but in your way, the max size is 20. What if I don't know the size of the string to be inputed. Then I have to use loops right? @Nobilis – user2316393 Jul 06 '13 at 15:29
  • @user2316393 If you don't know the size at all, then I recommend using [realloc](http://www.cplusplus.com/reference/cstdlib/realloc/?kw=realloc). Have a look at this link that discussed [this](http://www.mkyong.com/c/how-to-handle-unknow-size-user-input-in-c/) approach. But first have a good read on pointers and dynamic memory management. Alternatively you can prompt the user to enter a size and then create an array of that size. C99 allows such arrays. Btw, I've edit my post to point out some more problems with your code and suggestion on how you can fix your code. – Nobilis Jul 06 '13 at 15:38
  • How come this works then int i=0,a[10]; char c; while((c=getchar())!='\n') { scanf("%d",&a[i++]); c=getchar(); } Is it because, here I am asking for two different types of inputs, char and int? – user2316393 Jul 06 '13 at 15:57
  • @user2316393 This doesn't work, the code does not terminate when I enter a new line and it loops forever (for numerical input). In particular, please take note of the fact that you ask the user **twice** for input - once from `getchar` and once from `scanf`. – Nobilis Jul 06 '13 at 16:03
  • Okay, thanks! :). The edited version of my code given by you, helped! :) – user2316393 Jul 06 '13 at 16:09
  • @user2316393 I'm glad this has helped you but what you're doing is not the way you should get user input from the command line. Using `fgets` is a much safer, more standard way of doing so. I can only attribute this to some weird homework requirement. – Nobilis Jul 06 '13 at 16:11
  • This wasn't any homework. This is me trying to learn coding on my own, that's all. Could you please elaborate on how to use fgets so that I can use in future, or please give the link for same. – user2316393 Jul 06 '13 at 16:21
  • @user2316393 There are a ton of links in my post coloured in blue including one for `fgets` (in fact it's in the first sentence). There's also some commentary on how it's used. I've also included information on what the standard input is, what null-terminated string means and also references for `strlen`. Please re-read it and you will find it all there :) – Nobilis Jul 06 '13 at 16:51
2

To read a string into char array:

char *a = NULL;
int read;
size_t len;
read = getline(&a, &len, stdin);
//free memory
free(a);
Kostia
  • 271
  • 1
  • 9
2

Your code is this (except I've added a bunch of spaces to improve its readability):

 1  #include <stdio.h>
 2  void main()
 3  {
 4      char a[10], c;
 5      int i = 0;
 6      while ((c = getchar()) != '\n')
 7      {
 8          scanf("%c", &a[i++]);
 9          c = getchar();
10      }
11      for (i = 0; i < 11; i++)
12          printf("%c", a[i]);
13   }

Line-by-line analysis:

  1. OK (now I've added the space between #include and <stdio.h>).
  2. The main() function returns an int.
  3. OK (it is hard to get an open brace wrong).
  4. Since the return value of getchar() is an int, you need to declare c separately as an int.
  5. OK.
  6. Needs to account for EOF; should be while ((c = getchar()) != EOF && c != '\n'). You're still very open to buffer overflow, though.
  7. OK.
  8. Not OK. This reads another character from standard input, and doesn't check for EOF.
  9. Not OK. This too reads another character from standard input. But when you go back to the top of the loop, you read another character. So, as things stand, if you type abcdefg at the program, c is assigned 'a' in the loop control, then a[0] is assigned 'b', then c is assigned 'c', then the loop repeats with a[1] getting 'e'. If I'd typed 6 characters plus newline, the loop would terminate cleanly. Because I claimed I typed 7 characters, the third iteration assigns 'g' to c, which is not newline, so a[2] gets the newline, and the program waits for more input with the c = getchar(); statement at the end of the loop.
  10. OK (ditto close braces).
  11. Not OK. You don't take into account early termination of the loop, and you unconditionally access a non-existent element a[10] of the array a (which only has elements 0..9 — C is not BASIC!).
  12. OK.
  13. You probably need to output a newline after the for loop. You should return 0; at the end of main().

Because your input buffer is so short, it will be best to code a length check. If you'd used char a[4096];, I'd probably not have bothered you about it (though even then, there is a small risk of buffer overflow with potentially undesirable consequences). All of this leads to:

#include <stdio.h>

int main(void)
{
    char a[10];
    int c;
    int i;
    int n;
    for (i = 0; i < sizeof(a) && ((c=getchar()) != EOF && c != '\n')
        a[i++] = c;
    n = i;
    for (i = 0; i < n; i++)
        printf("%c", a[i]);
    putchar('\n');
    return 0;
}

Note that neither the original nor the revised code null terminates the string. For the given usage, that is OK. For general use, it is not.

The final for loop in the revised code and the following putchar() could be replaced (safely) by:

printf("%.*s\n", n, a);

This is safe because the length is specified so printf() won't go beyond the initialized data. To create a null terminated string, the input code needs to leave enough space for it:

    for (i = 0; i < sizeof(a)-1 && ((c=getchar()) != EOF && c != '\n')
        a[i++] = c;
    a[i] = '\0';

(Note the sizeof(a)-1!)

John Kugelman
  • 349,597
  • 67
  • 533
  • 578
Jonathan Leffler
  • 730,956
  • 141
  • 904
  • 1,278