0

If the user enters 5 as the first input, then the program should proceed with scanning 5 strings.

I tried:

int n;
scanf("%d",&n);
char a[100][10];

for (int i = 0; i < n; i++) {
    scanf("%s", &a[i][10]);
}

but that only scans a single word and then exits.

4
  • 1
    change to scanf("%s", a[i]); Commented Mar 27, 2014 at 11:07
  • a[i][10] is out of bounds, char a[100][10]; means that the highest index of a[i] is 9. Given that your scanf format specifies a string, you want to pass &a[i] Commented Mar 27, 2014 at 11:15
  • in this question string length max could be 10 and n is the number of string ?? what i mean is to create a matrix so that a[0][10] is the first string similarly other strings till n. correct me if i am wrong ?? Commented Mar 27, 2014 at 11:19
  • @VarunBehl: If you want the first string to start at a[0][10], which is the same as writing a[1][0], then just start the loop with int i = 1 and run it while i <=n. Keep in mind, though that the first 10 bytes (a[0][0] through a[0][9] will never be used in that case, and are just a waste of stack space Commented Mar 27, 2014 at 13:18

4 Answers 4

2

Given the fact that most of the answers given here are flawed in some way or another:
The accepted answer, for instance, states that a[i][10] accesses the tenth char in the row. This is completely false. As arrays are zero-indexed, this actually attempts to access the eleventh char in a row, which could well be out of bounds.
The same answer shows how a 2D array is divided up in rows and columns. This, too, is false. An array, be it 2D or 1D is a contiguous block in memory. Just one big row of chars. The actual layout of your array a[100][10], then looks like this. I've just noticed the answer mentions this, but still:

|/a[0][0] ===============================\\===============>a[99][9]\|
|-|-|-|-|-|-|-|-|-|-|-|-|-|-|-|-|-|-|-|-|-|-|-|-|-|-|-|-|-|-|-|-|-|-|

Just 100*10 chars in a row. Accessing a[1][0], then is the same as accessing a[0][10] or indeed a[10]. The out-of-bounds risk of using a[i][10] occurs if i is 99, because as you can see, the last char in the array is situated at a[99][9]. All memory beyond that point is off-limits.
The example given, in rows and column format where the input is a, b and c, then does not look like this:

_ _ _ _ _ _ _ _ _ a 
_ _ _ _ _ _ _ _ _ b
_ _ _ _ _ _ _ _ _ c

But rather, it'll look like this:

0 1 2 3 4 5 6 7 8 9 
_ _ _ _ _ _ _ _ _ _
a _ _ _ _ _ _ _ _ _ 
b _ _ _ _ _ _ _ _ _
c _ _ _ _ _ _ _ _ _

@TomFenech's answer is a lot better, using fgets here makes sense. However, to dot the i's and cross the T's: the nul-terminating char won't be read by fgets. The function will read at most n-1 chars, where n is the specified max length, as the documentation states:

The fgets function reads at most one less than the number of characters specified by n from the stream pointed to by stream into the array pointed to by s. No additional characters are read after a new-line character (which is retained) or after end-of-file.

However, fgets stops reading if, and only if it encounters a line-break or an EOF. It will not stop after encountering a NUL char. Keep that in mind, but in your case, it shouldn't be a worry.

When using fgets, however, you can find tons of snippets that call fflush(stdin); up front, to clean the input buffer. This invokes undefined behaviour, however, and you do well reading the buffer until it's empty first. Tom Fench left this out, so for completeness, I thought I'd mention it here, too. Other than that, I'd say his answer is accurate.

So, with this in mind, here's my suggestion:

Do away with your fixed-sized buffer. How many strings a will contain depends on user input. That means the array itself should be one of variable length. Thankfully, C (since C99) has just the thing you need: Variable Length Arrays - or VLA's for short would be preferable here. Here's what I wrote as a quick test/proof of concept:

#include <stdio.h>
#include <stdlib.h>

int main ( void )
{
    int i, n;
    puts("How many words do you wish to enter?");
    scanf(" %d", &n);//get size of input array
    while((i=getchar()) != EOF && i != '\n');//"flush" stdin
    char a[n][10];
    printf("Please enter %d words now\n", n);
    for (i=0;i<n;++i)
        fgets(a[i], 9, stdin);//get 9 char input, not 10 (10th char is nul terminator)
    for (i=0;i<n;++i)
        printf("Line %d: %s\n", i+1, a[i]);//print each input line
    return 0;//return
}

You can compile this on a *NIX system using gcc:

$ gcc -std=c99 your_code.c -o progName
$ ./progName

And run it. It works as expected.
Mind you, the input buffer for each entry is only 10 chars long. That means that a word like: "successful" is a no-go (it's 10 chars long, but a string requires a NUL-terminating char, too). I'd choose to use a bigger buffer for the actual input if I were you.
Since we're using a VLA, we no longer use up 1000 bytes of stack space by default (a[100][10] uses that much). If the value of n is 10, we could make our buffer 100 chars big, and still end up using no more memory than you are doing now. So perhaps consider using:

char a[n][24];
for (i=0;i<n;++i)
    fgets(a[i], 24, stdin);

Ideally, you'd clean the stdin buffer after each fgets call in the loop, too:

int j;//for clearing the buffer
for (i=0;i<n;++i)
{
    fgets(a[i], 24, stdin);
    if (strlen(a[i]) >= 23)//buffer overflow averted, clear stdin
        while ((j = getchar()) != EOF && j != '\n');//clear buffer
}

If you don't, and you leave the buffer at 10, you could encounter something like this:

Please enter 2 words now
successful?
Line 1: successfu
Line 2: l?

The full code, now looks something like this:

#include <stdio.h>
#include <stdlib.h>
#include <string.h> //add this

int main ( void )
{
    int i, j, n;//extra temp var
    puts("How many words do you wish to enter?");
    scanf(" %d", &n);
    while((j=getchar()) != EOF && j != '\n');
    char a[n][10];
    printf("Please enter %d words now\n", n);
    for (i=0;i<n;++i)
    {
        fgets(a[i], 10, stdin);
        if (strlen(a[i] >= 9)//<-- added
            while ((j=getchar()) != EOF && j != '\n');//added
    }
    for (i=0;i<n;++i)
        printf("Line %d: %s\n", i+1, a[i]);
    return 0;//return
}

The program compiles and runs in exactly the same way, though.
If you want to accommodate larger buffers if the user only wants to pass, say, 2 words as input, you can use VLA's for that, too:

#include <stdio.h>
#include <stdlib.h>
#include <string.h> //add this

//max buffer total 1000 chars is what you are using with a[100][10]
#define MAX_TOTAL_BUFFER 1000
//don't allow more than 80 chars per entry
#define MAX_SINGLE_BUFFER 80
//added for safety
#define MIN_SINGLE_BUFFER 10

int main ( void )
{
    int i, j, n. buf_len;
    puts("How many words do you wish to enter?");
    scanf(" %d", &n);
    buf_len = MAX_TOTAL_BUFFER/n; // int/int yields int 1000/3 == 333
    if (buf_len > MAX_SINGLE_BUFFER)
        buf_len = MAX_SINGLE_BUFFER;
    else if (buf_len < MIN_SINGLE_BUFFER) //mind you, risk of stack overflow here
        buf_len = MIN_SINGLE_BUFFER;
    while((j=getchar()) != EOF && j != '\n');
    char a[n][buf_len];
    printf("Please enter %d words (max %d chars long)\n", n, buf_len-1);
    for (i=0;i<n;++i)
    {
        fgets(a[i], buf_len, stdin);
        if (strlen(a[i] >= buf_len)//<-- added
            while ((j=getchar()) != EOF && j != '\n');//added
    }
    for (i=0;i<n;++i)
        printf("Line %d: %s\n", i+1, a[i]);
    return 0;//return
}

Play around with the max and minima for the buffers, and see how far you can push this until your stack eventually overflows. Also check the value of n after you get it from the user. If the user passes 0, this program doesn't deal with it properly. Either prompt the user again for a positive n, use a default value, or exit.
If n is negative, either use its absolute value (or multiply by -1), prompt again or exit... all of these things make for good exercises in interactive CLI C programs. Separating the logic, and writing functions will prove useful to turn this snippet into actual, useful code.

Sign up to request clarification or add additional context in comments.

6 Comments

If fgets reads, at most, one less character than the argument, why specify 9 rather than 10?
@TomFenech: nips, you're absolutely right. Sorry about that, will edit... that's just my being paranoid that prompted me to write that non-sense
Perhaps my answer isn't wrong after all then. I'm editing my phrasing to make it clearer.
@TomFenech: Like I said, I edited my answer, and mentioned your answer as being accurate. I am, however, leaving my answer here, as scanf(" %d ", &n); offers no guarantee the stdin buffer will be empty, and because I did suggest the use of VLA's, so the actual string buffers can be made larger, because 10 char buffers really are incredibly small
@TomFenech: Same to you... it's strange how the OP still accepts an answer that contains outright wrong information and chooses to ignore those answers that actually contain more relevant information...
|
1

scanf is dangerous in this situation, as a string longer than the length of your array could be entered. I would recommend using fgets:

#include <stdio.h>

int main()
{
  int n;
  scanf("%d ",&n); // note the added space
  char a[100][10];
  for (int i = 0; i < n; i++) {
      fgets(a[i], 10, stdin);
  }
  return 0;
}

The middle argument to fgets specifies the maximum number of characters to read. fgets will read max - 1 characters and adds a \0 (null byte) to the end of the string. Using this approach protects you from a buffer overflow and ensures that you end up with a valid string.

The added space in the scanf is so that the newline after the number is swallowed as well.

Comments

1

&a[i][10] evaluates to the address of the 11th element of the ith array in a - however since your arrays only have ten elements this will eventually go out of bounds.

You need the address of the i-th array. You can get that with a[i].

2 Comments

&a[i][10] is out of bounds, but if it wasn't it'd evaluate to the eleventh element of the array
Not quite, a[i] doesn't have an eleventh element. You haven't mentioned that the OP's code (&a[i][10]) is accessing memory out of bounds when i is 99...
0
char a[100][10];
_ _ _ _ _ _ _ _ _ _ 
_ _ _ _ _ _ _ _ _ _
_ _ _ _ _ _ _ _ _ _
         |
         |
    100 rOWS and 10 columns
         |
         |
_ _ _ _ _ _ _ _ _ _
_ _ _ _ _ _ _ _ _ _
_ _ _ _ _ _ _ _ _ _

When you do scanf("%s", &a[i][10]);, you are taking input from stdin for just the tenth character of every row.

For example if n=3 and inputs are a, b, c then it will logically look something like this(memory is continous but just for the sake of understanding I am using rows and columns).

_ _ _ _ _ _ _ _ _ a 
_ _ _ _ _ _ _ _ _ b
_ _ _ _ _ _ _ _ _ c

So to input a whole string you should just give the base address of row.

scanf("%s", &a[i]);

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.