0

How can I fill in a double or int array from a single, arbitrarily long, formatted (e.g. space delimited) keyboard line?

For instance:

Enter the elements of the array:
2 32 12.2 4 5 ...

should result in

=> array[0] = 2
=> array[1] = 32 etc.

I know that I can use scanf as follows, but that does not solve my problem, since each element should be entered one by one.

  /* Input data from keyboard into array */

  for (count = 1; count < 13; count++)
  {
      printf("Enter element : %d: ", count);
      scanf("%f", &array[count]);
  }

Thanks.

Barmar
  • 741,623
  • 53
  • 500
  • 612
hko
  • 139
  • 3
  • 10
  • 1
    Read in the entire string from the keyboard using `fgets`, then scan through the string - use `strtok` to find spaces, and finally interpret the "tokens" with `sscanf`. – Floris Sep 11 '13 at 21:14
  • 3
    *NEVER* use `gets()`! Read it in using `fgets()`, maybe. The `gets()` function is inherently, unfixably unsafe, and has been deprecated, excluded from the current version of the C standard, and marked Obsolete by POSIX. – This isn't my real name Sep 11 '13 at 21:18
  • You could enter a string of numbers comma separated such as "12.3,4.5,56.678, 12.1, 0.123" or as long as you want. Then hit return, scanf it in as a string. Use strtok to break it apart then use strtof() to convert the strings into floats, and assign them to a float array. – ryyker Sep 11 '13 at 21:18
  • 1
    @Floris: You cannot be serious about recommending `gets`! – Kerrek SB Sep 11 '13 at 21:18
  • OK OK sorry typo guys. I fixed it. My point was really "get the line in the form of a string and parse it". – Floris Sep 11 '13 at 21:19

3 Answers3

3

I know that I can use scanf as follows, but that does not solve my problem, since each element should be entered one by one.

No. If you leave off the newlines, that would work perfectly fine.


Generally, it is a good idea to avoid using scanf(), though -- it's not the most intuitive function to use (so to say). How about using fgets() to read in the line then parse it using strtof()?

char buf[LINE_MAX];
fgets(buf, sizeof buf, stdin);

char *s = buf, *endp;
int i = 0;
for (i = 0; i < 13; i++) {
    array[i] = strtof(s, &endp);
    s = endp;
}
  • Really? I don't think that you could type in a string of `1 2 3 4 5` followed by `CRLF`, and expect the above code to give you an array with the values 1 though 5 in it? Am I misinterpreting your answer, or the question? – Floris Sep 11 '13 at 21:16
  • 1
    @Floris I think you are misinterpreting both. –  Sep 11 '13 at 21:18
  • @H2CO3 - The drift of what you are communicating in your answer is fine, but it is not syntactically correct. Floris' question has more merit than you give credit. – ryyker Sep 11 '13 at 21:38
  • 1
    @ryyker Sorry, I don't understand what your problem is. OP thinks that one has to press Enter each time one wants `scanf()` to initiate a new conversion. I pointed out that it is not the case. I have even provided an alternative solution (which is similar to Floris' suggestion, just less complicated). I didn't say that Floris' comment was wrong either. I have honestly no idea what you are frowning upon... –  Sep 11 '13 at 21:44
  • @H2CO3 Would it be more efficient to have the loop condition be `i < 13 && *s != '\n'`? – verbose Sep 11 '13 at 22:32
  • @H2CO3 - Actually, I apologize, I did not recognize the syntax of the second argument of fgets, I have only seen it used as sizeof(arg). My bad. I learned yet another thing today- sizeof arg is syntactically correct. Thanks. – ryyker Sep 11 '13 at 22:33
  • @ryyker Well, no problem. We always learn new things every day. :) –  Sep 11 '13 at 22:34
  • @verbose Perhaps. I don't know. I can hardly be bothered to care about efficiency when accepting user input. I/O is so heavy and slow that iterating over the last few characters or not would not make a significant difference. –  Sep 11 '13 at 22:35
  • 1
    @verbose - regarding the loop condition, I am not sure if it would be more efficient, but I am pretty sure that including *s != '\n' would not be necessary given the OP question is asking how to do it without entering each time. He wants to enter an _arbitrarily long, formatted (e.g. space delimited) keyboard line_ – ryyker Sep 11 '13 at 22:44
  • It would seem that the loop condition should be more like `ii<13 && s!=NULL` since the number of arguments is variable – Floris Sep 11 '13 at 23:15
  • I think strtof is not defined in VS 2010. Therefore I could not check this answer. – hko Sep 12 '13 at 09:54
  • @H2CO3 how would you decide that the user actually put in all the elements (13 in this example), assuming that the user can also enter zeros ? I want to print an error if less than 13 elements are typed. strtod returns 0 when invalid (or insufficient) data is given. – hko Sep 12 '13 at 11:44
  • @KaganOguz you have to check the `endp` which `strtod()` sets to point to one after the last processed number. If there aren't any digits after that, then that's the end of input. –  Sep 12 '13 at 13:14
  • @H2CO3 can you also tell me how to read integers, too. I couldn't succeed yet. – hko Sep 12 '13 at 13:18
  • atoi() for reading string into int. @H2CO3 (sorry for butting in :)) – ryyker Sep 12 '13 at 13:53
  • @ryyker Better use `strtol()` instead. –  Sep 12 '13 at 14:39
  • @KaganOguz You should search for that in the documentation. –  Sep 12 '13 at 14:39
  • @H2CO3 - Agreed, long int would be more prudent, but question was how to convert into int. :) – ryyker Sep 13 '13 at 00:51
  • @ryyker I know that very well. That's not about the width of the integer. If I mean "use long instead of int", then I write "use long instead of int". I didn't - I wrote "use `strtol()` instead of `atoi()`. It's just that one should avoid `atoi()` and prefer `strtol()` to it. –  Sep 13 '13 at 04:34
1

You can't have an array that will hold both int AND double values. You can either have an array of int, or an array of double. If there are likely to be any doubles in your input, you should just declare an array of double.

You have to also set a maximum size for the array, and stop reading when that number of elements is filled. In C, you cannot have an array of dynamic size. If you really need to dynamically change the data structure based on the number of values, you're better off using a linked list.

scanf() is not a great tool for this, as it won't distinguish the newline at the end of the input from the space that separates numbers. Use fgets() to read the entire line and then sscanf() to split it into array elements.

Here's how to use the array:

double ary[MAX_ARRAY_SIZE];    // MAX_ARRAY_SIZE being some defined value
char buffer [512];
char* ptr = buffer;
int i = 0;

printf ("Enter your values separated by spaces: ");
fgets (buffer, sizeof (buffer), stdin);

while (i < MAX_ARRAY_SIZE && ptr) {
    sscanf (ptr, "%lf", &ary[i]);
    ptr++;
    i++;
    ptr = strchr(ptr, '\040');
}
verbose
  • 7,827
  • 1
  • 25
  • 40
  • Here is a working example of the code: http://ideone.com/SvyaF7. Note that the assumption is that only one space separates each value on the input line. If there are multiple spaces, this code won't work. @H2CO3's answer is more robust. – verbose Sep 12 '13 at 08:24
  • the error says "R6002 - floating point support not loaded". What am I missing ? – hko Sep 12 '13 at 09:51
  • I couldn't check @H2CO3's answer, is strtof not defined in VS 2010? – hko Sep 12 '13 at 09:57
  • With regard to @H2CO3's answer, you probably just need to `#include `. With regard to the R6002 error: http://runtimerrorfix.blogspot.com/2013/05/runtime-error-r6002-floating-point.html. – verbose Sep 12 '13 at 10:03
  • I have included stdlib.h but somehow it says strtof is undefined. No problem with strtod. – hko Sep 12 '13 at 10:17
  • Is there any function that I can replace `strtod` when reading integers. There is `strtol`, but why no such thing as `strtoi` ? – hko Sep 12 '13 at 12:19
  • `atoi()` does no error checking. `strtod()` is preferable for integers. Why do you need to replace it? – verbose Sep 12 '13 at 19:35
  • @verbose I did try to use it but I dont know why casting does not work in: `param[i] = (int)strtod(s, &endp);`. I get zeros in the array. – hko Sep 12 '13 at 20:13
  • @verbose I sent it to you – hko Sep 12 '13 at 20:24
  • Did you get it? Dont you mean your account is verbose ? – hko Sep 12 '13 at 21:06
0

You can do some work on variable initialization etc.. But this will do what you ask.

#include <ansi_c.h>

int main(void)
{
    char hold[20][10];
    double arr[20];//change size as necessary
    char *buf;
    char *toss;
    int i=-1, j=0;
    buf = malloc(260);
    toss = malloc(260);

    fgets(buf, 260, stdin);
    buf = strtok(buf, " ");
    while(buf)
    {
        strcpy(hold[++i], buf);
        arr[i] = strtod(hold[i], &toss);
        buf = strtok(NULL, " ");
    }

    for(j=0;j<i;j++)
    {
        printf("arr[%d]=%f\n", j, arr[j]);  
    }

    getchar();

    return 0;
}
ryyker
  • 22,849
  • 3
  • 43
  • 87
  • Thank you, this code works fine. Just need to make (j<=i) in the last for loop to print all the elements in the array. – hko Sep 12 '13 at 08:38