[英]Reading input for more than one array, line by line,without knowing the number of inputs to be given
I was given 3 arrays and the input for each array is given in a single line with space between each element. 给了我3个数组,每个数组的输入在一行中每个元素之间都有空格。
Example input: 输入示例:
3 2 1 1 1
4 3 2
1 1 4 1
So what I am trying to do is to assign all the elements of first line to array 1, second line to array 2 and third line to array 3. 所以我想做的是将第一行的所有元素分配给数组1,第二行将所有元素分配给数组2,第三行将所有元素分配给数组3。
#include <stdio.h>
int main()
{
int a[20],b[20],c[20],d[3];
int k=0;
char temp;
do{
scanf("%d%c", &a[k], &temp);
k++;
} while(temp != '\n');
d[0]=k;
k=0;
do{
scanf("%d%c", &b[k], &temp);
k++;
} while(temp != '\n');
d[1]=k;
k=0;
do{
scanf("%d%c", &c[k], &temp);
k++;
} while(temp != '\n');
d[2]=k;
return 0;
}
This is what I tried, but this code saves all the elements in the first array itself. 这是我尝试过的方法,但是这段代码将所有元素保存在第一个数组本身中。 Any help?
有什么帮助吗?
I've just tried your code and it works fine - a, b, c are filled with the numbers entered via stdin. 我刚刚尝试了您的代码,它可以正常工作-a,b,c充满了通过stdin输入的数字。
However, your primary problem is that scanf
is not line oriented. 但是,您的主要问题是
scanf
不是面向行的。 You should instead use fgets
to read the line in a string and parse it with strtok
and sscanf
. 您应该改用
fgets
读取字符串中的行,并使用strtok
和sscanf
对其进行解析。
Taking the recommendation to use fgets
is one thing, putting it into use the first time is quite another. 推荐使用
fgets
是一回事,第一次使用它是另一回事。 You use fgets
(or POSIX getline
) because they provide a mechanism for reading an entire line of text into a buffer at once. 您使用
fgets
(或POSIX getline
),因为它们提供了一种将整个文本行一次读入缓冲区的机制。 This eliminates the pitfalls inherent in trying to use scanf
for that purpose. 这消除了尝试为此目的使用
scanf
固有的陷阱。
While POSIX getline
will handle a line of any length for you, it dynamically allocates storage for the resulting buffer. 尽管POSIX
getline
将为您处理任意长度的行,但它会动态地为结果缓冲区分配存储空间。 fgets
on the other hand will read only as many characters as can be stored in the size you specify in the fgets
call (reserving space for the nul-character , as fgets
always provides a nul-terminated buffer) 另一方面,
fgets
只会读取您在fgets
调用中指定的大小可以存储的尽可能多的字符(为nul-character保留空间,因为fgets
始终提供以nul终止的缓冲区)
This means it is up to you to check that a complete line fit into the buffer you provided for fgets
use. 这意味着您需要检查是否有完整的行适合您提供给
fgets
使用的缓冲区。 Essentially you want to check whether the buffer is full and the last character is not the '\\n'
character. 本质上,您想检查缓冲区是否已满,并且最后一个字符不是
'\\n'
字符。 Note, you are not concerned with trimming the trailing newline here, just in checking for its presence to validate whether a complete line was read. 请注意,您不必担心在此处修剪尾随的换行符,而只是检查其是否存在以验证是否已读取完整的行。 So here you can check whether the length of buffer is your max size (minus
1
for the nul-character ) and the last character is not '\\n'
. 因此,您可以在此处检查缓冲区的长度是否为最大大小( nul-character减去
1
)并且最后一个字符不是'\\n'
。 If those two conditions exist, you have no way of knowing whether the entire line was read (but see the note after this example). 如果存在这两个条件,则无法知道是否已读取整行(但请参见本示例后面的注释)。 A simple approach to the validation whether a full line was read into
buf
is, eg 验证是否将整行读入
buf
一种简单方法是,例如
while (fgets (buf, MAXC, fp)) {
...
size_t len = strlen (buf); /* length for line validation */
/* validate whole line read into buf - exit on error */
if (len == MAXC - 1 && buf[len - 1] != '\n') {
fprintf (stderr, "error: line %d too long.\n", row + 1);
return 1;
}
( note : for the corner-case of a file without a POSIX eof
(end-of-file), eg without a '\\n'
following the last line of text, there is a chance you could actually read an exact buffer full of characters and have no trailing '\\n'
, but still have a complete read -- you can check for EOF
with a call to getchar()
and return the character to the buffer with putchar
if it is other than EOF
) ( 注意 :对于没有POSIX
eof
(文件结尾)的文件的特殊情况,例如,在文本的最后一行之后没有'\\n'
下,您实际上可能会读取一个完全为字符且没有尾随'\\n'
,但仍具有完整的读取-您可以通过调用getchar()
来检查EOF
,如果不是EOF
则可以使用putchar
将字符返回到缓冲区中)
Now on to handling your arrays. 现在开始处理数组。 Rather than declaring separate arrays of
20
int each, instead declare a 2D array of n
row of 20
int each. 与其声明每个
20
int的独立数组,不如声明一个n
行20
int的2D数组。 This makes handling the read and indexing much easier. 这使得处理读取和索引变得更加容易。
You also have the problem of having to capture the number of values you store in each row. 您还存在必须捕获每行中存储的值数量的问题。 While you can do a little indexing magic and store the number of values in each row as the first-column value, it is probably a bit easier just to have a separate array of
n
values where each index corresponds to the number of values store for each row in your 2D array. 虽然您可以做一些索引魔术操作,并将每行中的值数存储为第一列值,但仅具有
n
值的单独数组(每个索引对应于要存储的值数)可能会容易一些2D阵列中的每一行。 For example, 例如,
int row = 0, /* row count during read */
idx[ROWS] = {0}, /* array holding col count per row */
arr[ROWS][COLS] = {{0}}; /* 2D array holding each line array */
That way, each time you add a value to one of your rows, you simply increment the corresponding value in idx
, eg 这样,每次向一个行中添加一个值时,您只需在
idx
增加相应的值即可,例如
/* fill a value in row, then */
idx[row]++; /* update col-index for array */
With that background, you are finally ready to start filling your array. 在此背景下,您终于可以开始填充阵列了。 The approach is straight-forward.
该方法很简单。 You will:
你会:
fgets (buf, MAXC, fp)
; fgets (buf, MAXC, fp)
读取fgets (buf, MAXC, fp)
行; offset
, etc.); offset
等); buf
using sscanf
to repeatedly parse a single-integer from buf
until all integers are read; buf
使用sscanf
在buf
使用内部循环,反复从buf
解析单整数,直到读取所有整数; sscanf
on buf + offset
from the beginning), saving the number characters consumed (saved with the %n
format specifier to update offset
); buf + offset
从头开始调用sscanf
buf + offset
),保存消耗的字符数(用%n
格式说明符保存以更新offset
); offset
with the number of characters consumed, and repeat. offset
量,然后重复。 ( note: it is up to you to protect your array bounds to make sure you do not attempt to store more integer values in each array than you have storage for, and that you do not try and store more rows than you have storage for. So on each the outer and inner loop you will add a check to limit the number of rows and columns you read to the available storage) ( 注意:您必须保护自己的数组边界,以确保在每个数组中存储的整数值不要超过存储的整数,并且存储的行数不要超过存储的整数。因此,在每个外部和内部循环上,您都将添加一个检查,以限制读取到可用存储的行和列的数量)
Your read loops implementing the steps above could look like the following: 您实现上述步骤的读取循环可能如下所示:
/* constants for max rows, cols, and chars for read buf */
enum { ROWS = 4, COLS = 20, MAXC = 512 };
...
while (row < ROWS && fgets (buf, MAXC, fp)) { /* read each line */
int col = 0, /* col being filled */
nchr = 0, /* no. chars consumed by sscanf */
offset = 0, /* offset in buf for next sscaf call */
tmp = 0; /* temp var to hold sscanf conversion */
size_t len = strlen (buf); /* length for line validation */
/* validate whole line read into buf - exit on error */
if (len == MAXC - 1 && buf[len - 1] != '\n') {
fprintf (stderr, "error: line %d too long.\n", row + 1);
return 1;
}
while (col < COLS && /* read each value in line into arr */
sscanf (buf + offset, "%d%n", &tmp, &nchr) == 1) {
arr[row][col++] = tmp; /* assign tmp to array */
offset += nchr; /* update offset in buffer */
idx[row]++; /* update col-index for array */
}
row++; /* increment row for next read */
}
Putting it altogether, you could do something like the following: 综上所述,您可以执行以下操作:
#include <stdio.h>
#include <string.h>
/* constants for max rows, cols, and chars for read buf */
enum { ROWS = 4, COLS = 20, MAXC = 512 };
int main (int argc, char **argv) {
int row = 0, /* row count during read */
idx[ROWS] = {0}, /* array holding col count per row */
arr[ROWS][COLS] = {{0}}; /* 2D array holding each line array */
char buf[MAXC] = ""; /* buffer for fgets */
FILE *fp = argc > 1 ? fopen (argv[1], "r") : stdin;
if (!fp) { /* validate file open for reading */
fprintf (stderr, "error: file open failed '%s'.\n", argv[1]);
return 1;
}
while (row < ROWS && fgets (buf, MAXC, fp)) { /* read each line */
int col = 0, /* col being filled */
nchr = 0, /* no. chars consumed by sscanf */
offset = 0, /* offset in buf for next sscaf call */
tmp = 0; /* temp var to hold sscanf conversion */
size_t len = strlen (buf); /* length for line validation */
/* validate whole line read into buf - exit on error */
if (len == MAXC - 1 && buf[len - 1] != '\n') {
fprintf (stderr, "error: line %d too long.\n", row + 1);
return 1;
}
while (col < COLS && /* read each value in line into arr */
sscanf (buf + offset, "%d%n", &tmp, &nchr) == 1) {
arr[row][col++] = tmp; /* assign tmp to array */
offset += nchr; /* update offset in buffer */
idx[row]++; /* update col-index for array */
}
row++; /* increment row for next read */
}
if (fp != stdin) fclose (fp); /* close file if not stdin */
for (int i = 0; i < row; i++) { /* output the arrays read */
for (int j = 0; j < idx[i]; j++)
printf (" %3d", arr[i][j]);
putchar ('\n');
}
return 0;
}
Note: rather than using a fixed size 2D array, you can take things a step further and instead use a pointer-to-pointer-to-int (eg a double-pointer, int **arr;
) and dynamically allocate and reallocate pointers for rows, as required, and dynamically allocate and reallocate the storage assigned to each pointer to handle any number of integer values per-row. 注意:除了使用固定大小的2D数组,您可以更进一步,而可以使用指针到指针的整数 (例如,双指针,
int **arr;
)并动态分配和重新分配指针对于行,根据需要,并动态分配和重新分配分配给每个指针的存储,以处理每行任意数量的整数值。 While it is not that much additional work, that is left as an exercise to you when you get to dynamic allocation in your studies. 尽管没有太多额外的工作,但是当您在学习中进行动态分配时,这只是练习。 What you are doing with an differing number of column values per-row is creating a jagged array .
每行具有不同数量的列值的操作是创建一个锯齿状的数组 。
Example Input File 输入文件示例
Using your input file for testing, eg: 使用您的输入文件进行测试,例如:
$ cat dat/3arr.txt
3 2 1 1 1
4 3 2
1 1 4 1
Example Use/Output 使用/输出示例
Produces the following output: 产生以下输出:
$ ./bin/arr_jagged dat/3arr.txt
3 2 1 1 1
4 3 2
1 1 4 1
Look things over and let me know if you have further questions. 仔细检查一下,如果您还有其他问题,请告诉我。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.