1 2 3 4 5
1 2 3 4 5
1 2 3
2 5 7 8 9 8
I'm a beginner of C and I want to write a small program but I have this problem.
The problem is: if there is a file contains integers, the number of integers of each line is different but all within the maximum number of integers.
For example the integers above, the maximum number of integers for each line is 6, each line could have from 1 to 6 integers. The maximum number of integers will also change for each file.
How to store these numbers into a 2D array? Or store the integers into arrays line by line. (Don't worry about the empty values)
I have tried to use fscanf, but I don't know how to define the number of integers of each reading.
================================
Thanks everyone for the generous help, I've figured out using Joachim Pileborg's idea.
#define MAX_SIZE_BUFFER 1000
FILE *file;
int len = MAX_SIZE_BUFFER;
char sLine[MAX_SIZE_BUFFER];
int i, j, maxnumber = 6;
int *numbers, *temp;
char *sTok;
numbers = (int *) malloc(sizeof(int) * maxnumber);
for (i = 0; i < maxnumber; i++) {
numbers[i] = -1;
}
while (fgets(sLine, len, file) != NULL) {
i = 0;
sTok = strtok(sLine, " ");
while (sTok != NULL) {
numbers[i] = atof(sTok);
sTok = strtok(NULL, " ");
i++;
}
/* This temp stores all the numbers of each row */
temp = (int *) malloc(sizeof(int) * i);
for (j = 0; j < i; j++) {
temp[j] = numbers[j];
}
}
The code above is not completed, but it's the idea how I do this.
One way to solve your problem is to start by reading line by line (using e.g. fgets). Then for each line you need to separate the "tokens" (integers) which you can do with e.g. strtok in a loop. Finally, convert each "token" string to an integer using e.g. strtol.
let's try: fscanf(fp, "%d", value)
fp : file pointer.
"%d": format of the value that you want to read (it can be %c, %f, ...).
value: use it to keep the value you just read from the file.
Of course you should put it into the loop if you want to read all content in the file. EOF is the condition to break the loop.
Related
This question already has answers here:
fscanf into a 2d array in C
(2 answers)
Closed 4 years ago.
So i have a 20 x 20 array, and its all filled with -1.
I also have an input.txt which contains some numbers, for example :
2,3
5,6
How can i fill my array so that array[0][0] will be 2,
array[0][1] will be 3, array[1][0] will be 5, array[1][1] will be 6, and every other element will be -1.
I've tried with a for loop thats using fscanf until there is a new line, but that won't work.
I've tried with a for loop thats using fscanf until there is a new line, but that won't work.
Variations on fscanf(in, "%d,%d\n", &x, &y), as in OP's prior question, fail to detect end-of-line. The '\n' in the format will match any white-space on input including '\n', ' ', '\t',etc.
Simplistic usage of fscanf(..., "%d",...) can readily fail as "%d" will consume all leading white-space with no discrimination between '\n' and other white-spaces.
How can i fill my array ...
Although possible to use fscanf() to solve this task, consider fgets(), strtol().
The best approach is to use fgets() to reach a line: all characters up to and including the one final '\n'. Then use strtol(), strtoll(), etc. to read the integers.
long integers and spacing each needs reasonable less than 21 characters. To accommodate extra leading zeros spacing, etc, let use 2x the anticipated size needs.
#define CHAR_PER_NUMBER 21
#define NUM_PER_LINE 20
#define LINE_NUM 20
#define LINE_SIZE (NUM_PER_LINE * CHAR_PER_NUMBER * 2)
long array[LINE_NUM][NUM_PER_LINE];
// read data
for (int i = 0; i < LINE_NUM; i++) {
char buf[LINE_SIZE + 1]; // +1: room for the appended the null character
if (fgets(buf, sizeof buf, in) == NULL) {
buf[0] = '\0';
}
// Now parse the line
char *p = buf;
for (int j = 0; j < NUM_PER_LINE; j++) {
char *endptr;
array[i][j] = strtol(p, &endptr, 10);
if (p == endptr) {
array[i][j] = -1; // no conversion
}
p = endptr; // advance to the next number
}
}
Additional concerns including handling pathological long lines, values outside the long range, I/O error handling and efficiency details.
Should input consists of text representing floating-point, a more generous max size per value is warranted.
Try using "end of file"(eof), where m and n are the rows and columns
for (i = 0; i < m && !feof(input); i++)
for (j = 0; j < n && !feof(input); j++)
fscanf(input, "%f", &a[i][j]);
If the size of the array (m and n) is also given in the file write an if condition before
if (!feof(input))
fscanf(input, "%d %d", &m, &n);
for (i = 0; i < m && !feof(input); i++)
for (j = 0; j < n && !feof(input); j++)
fscanf(input, "%f", &a[i][j]);
I'm trying to display my output in a 4X4 format. The program receives name of a text file then get the values in the text file and store in the 2D array. Then later displays them like this
7 2 4 5
5 2 6 4
2 2 5 5
9 2 4 5
But the problem is, it doesn't display like that, I'm not sure if it's my loop or what. Any ideas. it runs fine with no errors but the numbers don't display right. Here's my code
int main () {
int i = 0;
int j = 0;
int value = 0;
int a[4][4];
char ch, file_name[100];
FILE *fp;
printf("Enter file name?");
gets(file_name);
fp = fopen("file.txt", "r");
if (fp == NULL)
{
perror("Error \n");
}
else
{
// printf("\n");
while (!feof(fp) && fscanf (fp, "%d ", &value))
{
a[i][j] = value;
for ( i = 0; i < 4; i++ )
{
for ( j = 0; j < 4; j++ )
{
printf("%d ",a[i][j] );
}
printf("\n");
}
}
}
fclose(fp);
return 0;
}
Your code suffers from various problems since you are mixing the code that reads the input and code that writes the output in one while loop.
Separate the code that reads the input and the code that creates the output. Ideally, put them into different functions.
Declare the functions as:
void readData(FILE* in, int a[4][4]);
void writeData(FILE* out, int a[4][4]);
Use them as:
int main()
{
int a[4][4];
// Your code to open the file.
readData(in, a);
writeData(stdout, a);
}
Implement them as:
void readData(FILE* in, int a[4][4])
{
for ( i = 0; i < 4; i++ )
{
for ( j = 0; j < 4; j++ )
{
if ( fscanf(in, "%d", &a[i][j]) != 1 )
{
printf("Unable to read an array element.\n");
exit(0);
}
}
}
}
void writeData(FILE* out, int a[4][4])
{
for ( i = 0; i < 4; i++ )
{
for ( j = 0; j < 4; j++ )
{
fprintf(out, "%d ", a[i][j]);
}
fprintf(out, "\n");
}
}
Well, let's take your problems apart a piece at a time. First, the salient part of your code regarding input and attempted output:
int i = 0;
int j = 0;
int value = 0;
int a[4][4];
...
while (!feof(fp) && fscanf (fp, "%d ", &value))
{
a[i][j] = value;
for ( i = 0; i < 4; i++ )
{
for ( j = 0; j < 4; j++ )
{
printf("%d ",a[i][j] );
}
printf("\n");
}
}
Before we look at the !feof problem. let's look at the overall logic of your loop structure. When you enter your while loop, the values of i = j = 0;. Presuming your file is open and there is an integer to read, you will fill value with the first integer in the file and then assign that value to the first element of your array with:
a[i][j] = value;
Now, you have stored 1-integer at a[0][0]. (all other values in a are uninitialized and indeterminate) Inexplicably, you then attempt to output the entire array, ... uninitialized values and all.
for ( i = 0; i < 4; i++ )
{
for ( j = 0; j < 4; j++ )
{
printf("%d ",a[i][j] );
}
printf("\n");
}
Attempting to access an uninitialized value invokes Undefined Behavior (your program is completely unreliable from the first attempt to read a[0][1] on). It could appear to run normally or it could SegFault or anything in between.
You need to complete the read of all values into your array before you begin iterating over the indexes in your array outputting the values.
But wait... there is more... If you did not SegFault, when you complete the for loops, what are the values of i & j now? Your loops don't complete until both i and j are 4, so those are the values they have at the end of the first iteration of your while loop.
Now let's go to the next iteration of your while loop. Presuming there are two integer values in the file you are reading, you read the second integer into value. What happens next? You one-up yourself. After already invoking undefined behavior 15 times by attempting to read 15 uninitialized values a[0][1] -> a[3][3], you then attempt to write beyond the bounds of a with:
a[4][4] = value; /* remember what i & j are now? */
You then hit your for loops..., again with a[0][1] holding the only validly initialized value and the cycle repeats.
But wait..., there is more... After having read the last integer in your file, you arrive at the beginning of your while loop one last time:
while (!feof(fp) && fscanf (fp, "%d ", &value))
You test !feof(fp) and no EOF has been set because your last read was a valid read of the last integer which completed with the last digit and did not trigger a stream error, so you proceed to fscanf (fp, "%d ", &value) which now returns EOF (e.g. -1), but since you simply test whether fscanf(..), -1 tests TRUE so off you go again through the entire body of your loop invoking undefined behavior at least 16 more times.
Are you beginning to understand why the output may not have been what you wanted?
You have already had a good answer on how to go about the read and print. I'll offer just an alternative that does not use any functions so it may help you follow the logic a bit better. The following code just reads from the filename given as the first argument, or from stdin by default if no argument is given. The code validates that the file pointer points to a file that is open for reading and then enters a while loop reading an integer at a time into &array[rows][cols] with fscanf and validating the return of fscanf is 1. Anything else is considered failure.
The remainder of the read loop just increments cols until is reaches NCOLS (4 here - being the number of columns per-row), then it increments the row-count in rows and sets the column-index cols back to zero.
A final validation is performed before output to insure NROWS of integers were read and that cols was set to zero during the final iteration of the read-loop. The contents of array is then output. The code is fairly straight-forward:
#include <stdio.h>
#define NROWS 4
#define NCOLS NROWS
int main (int argc, char **argv) {
int array[NROWS][NCOLS] = {{0}}, /* declare and intialize array */
rows = 0, cols = 0; /* rows / columns index */
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;
}
/* validate no more than NROWS of NCOLS integers are read */
while (rows < NROWS && fscanf (fp, "%d", &array[rows][cols]) == 1) {
cols++; /* increment column */
if (cols == NCOLS) { /* if row full */
rows++; /* increment rows */
cols = 0; /* zero columns */
}
}
if (fp != stdin) fclose (fp); /* close file if not stdin */
if (rows != NROWS || cols) { /* validate rows = NROWS & cols = 0 */
fprintf (stderr, "error: read only %d rows and %d cols.\n",
rows, cols);
return 1;
}
for (int i = 0; i < NROWS; i++) { /* output stored values */
for (int j = 0; j < NCOLS; j++)
printf (" %2d", array[i][j]);
putchar ('\n');
}
return 0;
}
(you have already been advised not to use gets which is subject to easy buffer overflow and so insecure it has been completely removed from the C11 library. If your professor continues to suggest its use -- go find a new professor)
Example Input File
$ cat dat/arr2dfscanf.txt
7 2 4 5
5 2 6 4
2 2 5 5
9 2 4 5
Example Use/Output
$ ./bin/arr2dfscanf <dat/arr2dfscanf.txt
7 2 4 5
5 2 6 4
2 2 5 5
9 2 4 5
Also note, that by reading with fscanf in this manner, it doesn't matter what format your input is in -- as long as it is all integer values. This will produce the same output:
$ echo "7 2 4 5 5 2 6 4 2 2 5 5 9 2 4 5" | ./bin/arr2dfscanf
Look things over and let me know if you have further questions.
There is an array x and I want to put its elements in arrays y and z based of some if condition.
int x[10],y[5],z[5];
for(for x array)
if(some condition)
{
//put in y
}
else {
//put in z
}
What I am not able to figure out is how to keep track of indexes in array y and z while assigning the elements. Any help/suggestion is appreciated. Thnak you.
When dealing with any arrays, C doesn't provide any bounds checking, that responsibility is left solely to you as the C-programmer. Attempting to access an element outside the defined array bounds invokes Undefined Behavior.
To prevent straying off into undefined behavior, always keep track to the current array index (when filling) and test against a Max array index. While you can use sizeof array / sizeof *array be aware that is only valid within the scope where the array was declared. Once the array is passed as a parameter to a function, the first level of indirection is converted to a pointer and sizeof thereafter will return sizeof (a pointer) not the array size.
Don't use magic numbers in your code. If you need constants in your code, define them at the top of your code, either with, e.g. #define XMAX 10, or use an enum to declare them. That way, if you ever need to change the bounds (or whatever the constant is used for), you have a single location at the top, and you don't have to go picking though every loop or conditional you hardcoded some magic number in.
A quick example in your case separating the odd/even numbers in x into y & z could be done by:
#include <stdio.h>
enum { YZMAX = 5, XMAX = 10 };
int main (void) {
int x[XMAX] = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9},
y[YZMAX] = {0},
z[YZMAX] = {0};
size_t yndx = 0, zndx = 0;
for (int i = 0; i < XMAX; i++)
if (yndx < YZMAX && (x[i] & 1) == 0) {
y[yndx++] = x[i];
}
else if (zndx < YZMAX) {
z[zndx++] = x[i];
}
for (int i = 0; i < YZMAX; i++)
printf (" y[%d] : %d z[%d] : %d\n", i, y[i], i, z[i]);
return 0;
}
Example Use/Output
$ ./bin/xyzindex
y[0] : 0 z[0] : 1
y[1] : 2 z[1] : 3
y[2] : 4 z[2] : 5
y[3] : 6 z[3] : 7
y[4] : 8 z[4] : 9
Reading a 2D Array from Command Line Arguments
Whether you are reading a 1D array or 2D array, the process is the same. The only thing that changes is keeping up with one additional index. In your comment, you provide the additional twist of having multiple integers contained within a single command-line argument string. While it may appear confusing at first, if you think about it, it is no different than reading multiple integers from a single line of text in a file.
While you suggest two arguments of "2 4" and "3 5", there is no reason to worry about how many integers are in each argument. Handling "2 4 3" and "5" would work the same (or "2 4 3 5" or 2 4 3 5 for that matter)
note: you will generally not want to provide array values as command-line arguments (you can, but...) you generally want to read values from a file (or stdin - a file as well). Command line arguments are generally used to influence code behavior (e.g., --help, etc..) or provide filenames from which values can be read rather than providing the values themselves. It's up to you. (for simple test code it is fine to use the arguments for anything you need)
The key is just to read each integer (regardless of which argument it comes from) update your row/column indexes, and take whatever additional steps are required before returning to read the next integer. For example:
#include <stdio.h>
#define ROW 2
#define COL 2
#define BASE 10
int main (int argc, char **argv) {
if (argc < 2) { /* validate at least one argument string given */
fprintf (stderr, "error: insufficient input.\n"
"usage: %s [followed by %d integers]\n",
argv[0], ROW + COL);
return 1;
}
int arr[ROW][COL] = {{0}}, /* array */
row = 0, col = 0, /* row / col indexes */
ndx = 1; /* argument index */
/* loop over each argument until array filled.
* you don't know how many integers could be
* in each argument., e.g. ("2 4" and "3 5")
*/
while (ndx < argc) {
char *p = argv[ndx]; /* pointer to current argument */
int offset = 0, tmp;
/* convert each int in argument and get offset in arg for next */
while (sscanf (p, "%d%n", &tmp, &offset) == 1)
{
arr[row][col++] = tmp; /* assign value to element */
if (col == COL) /* test if column full */
row++, col = 0; /* increment row, zero column */
if (row == ROW) /* test if array full */
goto done; /* goto required to break 2 loops */
p += offset; /* increment p by offset */
}
ndx++; /* process next argument */
}
done:;
for (int i = 0; i < ROW; i++) { /* for each row */
for (int j = 0; j < COL; j++) /* for each col */
printf (" %2d", arr[i][j]);
putchar ('\n');
}
return 0;
}
Example Use/Output
$ ./bin/array_2d_args "2 4" "3 5"
2 4
3 5
$ ./bin/array_2d_args "2 4 3" "5"
2 4
3 5
$ ./bin/array_2d_args "2 4 3 5"
2 4
3 5
$ ./bin/array_2d_args 2 4 3 5
2 4
3 5
Reading from a file would work the same way. Instead of looping over arguments, you would simply loop over lines read with fgets processing the integers in each line of text read with sscanf or handling both the read and conversion of single values with fscanf.
note: there are advantages in using strtol for the conversion to integer rather than sscanf, as it provides a great deal more error handling information, but also requires a bit of additional code to preform the error checking.
Reading values from a file or stdin
As noted above, in many cases it is actually easier to read directly from a file rather than using command-line arguments. Here is a short example. In this case rather than reading an integer then and handling the indexes, we use two loops to limit the number of integers read to the number of times the loops execute. Either way is fine:
#include <stdio.h>
#define ROW 2
#define COL 2
int main (int argc, char **argv) {
int arr[ROW][COL] = {{0}};
/* open filename given by argv[1] (or use stdin as default) */
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;
}
for (int i = 0; i < ROW; i++) /* for each row */
for (int j = 0; j < COL; j++) /* for each col */
if (fscanf (fp, "%d", &arr[i][j]) != 1) { /* read element */
/* handle error */
fprintf (stderr, "error: invalid input arr[%d][%d].\n", i, j);
return 1;
}
if (fp != stdin) fclose (fp); /* close file if not stdin */
for (int i = 0; i < ROW; i++) { /* for each row */
for (int j = 0; j < COL; j++) /* for each col */
printf (" %2d", arr[i][j]);
putchar ('\n');
}
return 0;
}
Example Input File
$ cat dat/2x2.txt
2 4
3 5
Example Use/Output
$ ./bin/array_2d_file <dat/2x2.txt
2 4
3 5
note: there is no need that the input be in rows or columns since you are reading a single integer at a time with fscanf -- and -- the "%d" format specifier will skip all leading whitespace (including the '\n') before reading the next number. So the input can be a on a single line or on 4-lines, e.g.
All on one line:
$ echo "2 4 3 5"
2 4 3 5
$ echo "2 4 3 5" | ./bin/array_2d_file
2 4
3 5
or mixed on multiple lines
$ printf "2\n4\n3\n\n5\n"
2
4
3
5
$ printf "2\n4\n3\n\n5\n" | ./bin/array_2d_file
2 4
3 5
or
$ printf "2\n4 3\n\n5\n"
2
4 3
5
$ printf "2\n4 3\n\n5\n" | ./bin/array_2d_file
2 4
3 5
Look things over in all answers and let me know if you have further questions.
For statically defined arrays;
int x[10],y[5],z[5];
for(for x array)
if(some condition)
{
//yindex is the index of the y array where you are going to assign the value
if(yindex < sizeof(y) / sizeof(y[0]))
{
y[yindex] = value;
}
}
you can give like that condition if you will initialize at least one array (y or z) with 0, maybe it will be helpful for you. Example:
#include<stdio.h>
int main()
{
//put values in x array otherwise it will take by default garbage value.
int i, j, k, x[10], y[5]={0}, z[5];
for(i=0; i<10; i++)
{
scanf("%d",&x[i]); //for console input.
}
for(i=0, j=0, k=0; i<10; i++)
{
if(y[j]==0 && j<5) //if(y[j]==0)
{
//put in y
y[j]=x[i];
printf("%d ",y[j]);
j++;
} else {
//put in z
z[k]=x[i];
printf("%d ",z[k]);
k++;
}
}
}
when you assign size only like x[10] without assigning any elements in C then it will store garbage values in array so if you want to store one array to another array then have to give condition for if() whatever you want to do.
int main() {
#define MEMSIZE 100
int memory[MEMSIZE] = {0};
int i = 0;
char *temp = malloc(sizeof(100));
fgets(temp, MEMSIZE, stdin);
for (i = 0; i < (sizeof(memory)/sizeof(int)); i++) {
memory[i] = temp[i];
}
for (n = 0; n < 10; n++) { // Print contents
printf("%d - %d\n", n, memory[n]);
}
}
So today I have what seems to be a very simple question. I am taking a file from stdin, using:
./a.out < filename
My main goal is to take in the numbers provided in the file, and store them into a 1 dimensional array. My current use of fgets() works correctly, reading in line one and copying those elements into my 1D array (their ASCII values converted to int). Now, to read in my next lines, if I call fgets() again, the next line is read but it is then stored in the same place as the first values, thus overwriting them in my array in position 0-3. These values need to be stored successively in my array until EOF.
The file is in the format:
1234
5678
...
#include <stdio.h>
#define MEMSIZE 100
int main() {
int memory[MEMSIZE] = {0};
int i,n;
for (i = 0; i <MEMSIZE; i++){
if(fscanf(stdin,"%d", (memory+i))==EOF){
break;
}
}
//i is the number of ints you got
for (n = 0; n < i; n++) { // Print contents
printf("%d - %d\n", n, memory[n]);
}
return 0;
}
I dont see a reason to use dynamic allocation over here as a temp variable.
If the file is list of numbers, just read as a number, no need for fgets over here, if you still want to read it as a string, have a look at atoi func
sizeof(memory)/sizeof(int)= (sizeof(int)*MEMSIZE)/sizeof(int)= MEMSIZE
You shouldn't just loop MEMSIZE times, you need to know when it EOF
I dont know why you assumed in the printing loop that 10 is enough, i changed it to i which is number of elements
You didnt define n
I hope that i helped.
This is my code so far:
#include "stdafx.h"
#define SIZE 200
int _tmain(int argc, _TCHAR* argv[])
{
FILE * ifp = NULL;
int inputArray[SIZE];
int i, j;
int c;
ifp = fopen("testfile.txt", "r");
for (i = 0; i <= SIZE; ++i)
fscanf(ifp, "%d", &inputArray[i]);
/*fscanf(ifp, "%d", */
for (i = 0; i <= SIZE; i++)
printf("%d", inputArray[i]);
return 0;
}
So I have a file that has nnumbers in it like:
3
5 5 3
6
3 2 6 4 1 1
The code above seems to work in getting the numbers into an array like 3 5 5 3 6 3 2...etc.
But then, the array size is 200. So the rest of the space not used in the array isn't just blank. It has a huge, weird numbers in it
so when I print it out, it it prints
35536326411 -858993460 -858993460
it prints that -858993460 to what I assume is about 200 times.
I'm a total noob in C and in programming. I asked the professor about the array size and he said just set it to a large number like 100 or 200 because trying to set the size of the array to a variable that can be changed (or something to that concept) is complicating and isn't at our level quite yet.
I need to do math with these numbers and I don't want to include those -858993460 things in my calculations. How would I determine where in the array is the last element that was actually declared?
Someone please point me into the right direction...
for (i = 0; i <= SIZE; ++i)
should be
for (i = 0; i < SIZE; ++i)
Else you have array out of bound access which will lead to undefined behavior.
for (i = 0; i < SIZE; ++i)
{
if(fscanf(ifp, "%d", &inputArray[i]) != 1)
break;
}
Set all elements to 0 using
memset(array,0,sizeof(array));
You can check the return value of fscanf() and once it returns failure [return !=1], you should stop scanning anymore.
Further, you can use that i-1 value for printing valid elements.
Also, you should change your loop limit to i < SIZE to avoid off-by-one error.
Then, you can initialize the local variables to avoid them having garbage values. You can use memeset() or initializer-lists to get that part done.
Don't define SIZE, make it a variable that will contains real count of number in file after reading.
size_t SIZE = 0;
for (SIZE = 0; ; ++SIZE)
{
if (fscanf(ifp, "%d", &inputArray[i]) == EOF)
break;
}