Add elements to two arrays based on condition - c

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.

Related

The output is weird on my C Console App. Any ideas?

I want to make an app that determines whether the given input is a positive number, and then prints them out if there are more than 2 positive numbers, but there is a weird output which I've been trying to fix for a few hours.
Note : I'm somewhat of a beginner in C.
#include <stdio.h>
int main() {
const char arr[][20] = {"First Number : ", "Second Number : ", "Third Number : "};
int numbers[2]; // number list
int posNumbers[2]; // positive number list
int n = 0; // n for itinerating posNUmbers
for ( int i = 0 ; i <= 2; i++) {
printf("%s", arr[i]);
scanf("%i", &numbers[i]);
} // puts input in array
for ( int i = 0 ; i <= sizeof(numbers) / sizeof(numbers[0]) + 1 ; i++ ) {
if (numbers[i] > 0) {
posNumbers[n + 1] = numbers[i];
}
} // adds positive in array
if (sizeof(posNumbers) / sizeof(posNumbers[0]) + 1 > 1) {
printf("There are atleast 2 pos numbers, which are : \n");
for ( int i = 0; i <= sizeof(posNumbers) / sizeof(posNumbers[0]) + 1 ; i++) {
printf("%i", posNumbers[i]);
}
} else {
printf("THere are not enough positive numbers.");
}
}
Output : There are atleast 2 pos numbers, which are : 4419368778941968054388
You have several misconceptions about arrays and the use of sizeof that cause you to attempt to access values beyond the end of your numbers and posNumbers arrays that invokes Undefined Behavior1 in your code. You further invoke Undefined Behavior when you attempt to read from uninitialized elements in the posNumbers array.
In C, arrays are:
zero based. Meaning that an array of nelem elements has valid indexes of 0 <= index < nelem,
when looping over all elements in an array, you loop from i = 0; i < nelem; i++,
if you fail to initialize your arrays all zero and do not fill all elements and attempt to loop over all elements in your array, you invoke Undefined Behavior when you attempt to access the uninitialized element (lesson -- initialize all arrays to begin with),
when you use sizeof array / sizeof array[0], you get the total number of elements in the array, not the number of elements filled,
your loop over posNumbers ignores the fact that less than all elements can be filled invoking Undefined Behavior if you attempt to read from an uninitialized element of the array,
when filling less than all values in an array, simply keep a counter to track the number of elements filled, you have n declared already.
Additional points to consider:
avoid using MagicNumbers in your code and instead #define a constant. This helps avoid the problems you are having with 2,
above all learn you cannot use scanf() (or any user input function) correctly unless you check the return, especially where numeric conversions are involved. What if the user enters "four" instead of 4?
Putting it altogether, and making a few additional changes to your output calls, you can rewrite your code to avoid the problems above as:
#include <stdio.h>
#define NVALS 3 /* if you need a constant, #define one (or more) */
int main (void) {
/* an array of pointers to the string-literals is fine */
const char *arr[] = { "First Number : ",
"Second Number : ",
"Third Number : " };
int numbers[NVALS] = {0}, /* initialize all arrays */
posNumbers[NVALS] = {0},
n = 0;
/* loop NVALS times reading number input */
for (int i = 0 ; i < NVALS; i++) {
/* no conversion involved, fputs is fine for end-of-line control */
fputs (arr[i], stdout);
/* you can't use scanf correctly unless you CHECK THE RETURN
* to validate each conversion was successfully completed
*/
if (scanf("%i", &numbers[i]) != 1) {
fputs ("error: invalid integer input.\n", stderr);
return 1;
}
/* compare if numbers[i] positive */
if (numbers[i] > 0) {
posNumbers[n++] = numbers[i];
}
}
if (n > 1) { /* check if at least two numbers positive */
puts ("\nThere are atleast 2 pos numbers, which are :");
for (int i = 0; i < n; i++) {
printf ("%i\n", posNumbers[i]);
}
}
else {
puts ("\nMust have at least two positive numbers.");
}
}
(note: a good compiler will convert printf ("const string"); to fputs ("const string", stdout); for you, but choosing fputs() over the variadic printf() when there are no conversions involved indicates you understand how to choose the proper tool for the job on your own)
Example Use/Output
If less than two positive integers:
$ ./bin/threeposnumbers
First Number : -10
Second Number : 0
Third Number : 4
Must have at least two positive numbers.
If the two positive numbers are provided:
$ /bin/threeposnumbers
First Number : -10
Second Number : 2
Third Number : 4
There are atleast 2 pos numbers, which are :
2
4
If all positive numbers are provided:
$ ./bin/threeposnumbers
First Number : 10
Second Number : 2
Third Number : 4
There are atleast 2 pos numbers, which are :
10
2
4
(if you are old enough, you will recall the special significance of those numbers for a specific soft-drink marketing campaign, hint: initials DP :)
Handling non-integer input:
$ ./bin/threeposnumbers
First Number : -10
Second Number : two
error: invalid integer input.
Let me know if you have further questions.
footnotes:
1.) See:
Undefined, unspecified and implementation-defined behavior and
What is indeterminate behavior in C++ ? How is it different from undefined behavior? and
Undefined behavior
You say you want to store 3 numbers but you are declaring your array size to be 2. If you want to store 3 numbers this code:
int numbers[2]; // number list
int posNumbers[2]; // positive number list
Should be
int numbers[3]; // number list
int posNumbers[3]; // positive number list
You are supposed to declare the array sizes as how big as you want them but you can only use up to size - 1 since indexes start from 0.
Also you should probably fix the things that #WeatherVane is stating in the comments.
Addendum on the answers: you can interleave then in a struct to make it clearer which variables go together. This can also reduce the number of times you repeat yourself.
You have: a) a fixed number of numbers to enter, and b) you are going to copy all the positive numbers to a second, possibly smaller, array. The simplest is to make an equal-size array and explicitly have the size. I would refactor the code as such,
#include <stdio.h>
int main(void) {
struct {
const char *title;
int number;
} arr[] = { { "First", 0 }, { "Second", 0 }, { "Third", 0 } };
struct {
size_t size;
int number[sizeof arr / sizeof *arr];
} positives;
const int arr_size = sizeof arr / sizeof arr[0];
// enter numbers
for ( size_t i = 0 ; i < arr_size; i++) {
printf("%s Number : ", arr[i].title);
if(scanf("%i", &arr[i].number) != 1) return 1;
}
// adds positive in array
positives.size = 0;
for ( size_t i = 0 ; i < arr_size ; i++ ) {
if (arr[i].number > 0) {
// bounded by arr_size
positives.number[positives.size++] = arr[i].number;
}
}
if (positives.size >= 2) {
printf("There are atleast 2 pos numbers, which are : \n");
for ( size_t i = 0; i < positives.size ; i++) {
printf("%i\n", positives.number[i]);
}
} else {
printf("THere are not enough positive numbers.\n");
}
}

How complete a matrix with the information of a file in C?

I'm learning C, but I have a problem with an exercise. I need to fill a matrix that I started with zeros, with the information of a file. The file contains some coordinates and I need to put in the matrix the numbers that contain the file, but in the row of coordinates previous to which the file gives me.
For example, if I have this file:
2,3 4 3 1
3,1 3 2 2
1,4 1 2 8
I need my final matrix to look like this:
0 0 0 1 2 8
0 0 4 3 1 0
3 2 2 0 0 0
0 0 0 0 0 0
My code: (that only opens the file and creates the matrix because I'm looking for information or examples, but I can not find anything useful)
#include <stdio.h>
int main(){
FILE *data;
data = fopen("example.txt","r");
if (data == NULL)
{
printf("\nERROR\n");
return -1;
}
int row = 4;
int col = 6;
int matrix[row][col];
for (int x = 0; x < row; ++x)
{
for (int y = 0; y < col; ++y)
{
matrix[x][y]=0;
}
}
fclose(data);
for (int x = 0; x < row; ++x)
{
for (int y = 0; y < col; ++y)
{
printf("[%d]",matrix[x][y]);
}
printf("\n");
}
return 0;
}
There are many, many ways to do this. If you know you will have 2 coordinates and 3 values per-line, then one of the easiest, and most robust ways of handling the read and parsing the data from each line, is to read each line into a buffer with fgets and then parse the line into the individual coordinates with sscanf.1 While you could accomplish the same thing with a single call to fscanf, reading with fgets will insure you consume an entire line of data each time and allows independent validation of your (1) read of data from the file; and (2) the parsing of the data into your coordinates and values.
You then simply need to map your coordinates into valid C-indexes by subtracting 1 (remember arrays in C a zero-based not one-based), check to make sure your coordinates are valid so that writing 3 values beginning at your indexes do not write beyond the bounds of your array, and finally, loop writing your 3-values to the x row beginning at the y index.
A simple implementation could be:
#include <stdio.h>
#define NVAL 3 /* if you need a constant, #define one (or more) */
#define ROW 4
#define COL 6
#define MAXC 1024
int main (int argc, char **argv) {
char buf[MAXC]; /* buffer to hold each line read with fgets */
int matrix[ROW][COL] = {{0}}; /* 2D array initialized all zero */
/* use filename provided as 1st argument (stdin by default) */
FILE *fp = argc > 1 ? fopen (argv[1], "r") : stdin;
if (!fp) { /* validate file open for reading */
perror ("file open failed");
return 1;
}
while (fgets (buf, MAXC, fp)) { /* read each line into buf */
int x, y, data[NVAL] = {0}; /* declare coords/data vars */
if (sscanf (buf, "%d,%d %d %d %d", /* parse line into values */
&x, &y, &data[0], &data[1], &data[2]) != 5) {
fputs ("error: invalid line format.\n", stderr);
continue; /* skip to next line on error */
}
x = x - 1; /* convert coords to zero based index for C */
y = y - 1;
if (x < ROW && y <= COL - NVAL) { /* check valid indexes */
for (int i = 0; i < NVAL; i++) /* loop over each value */
matrix[x][y++] = data[i]; /* write numbers to array */
}
}
if (fp != stdin) fclose (fp); /* close file if not stdin */
for (int i = 0; i < ROW; i++) { /* loop over rows */
for (int j = 0; j < COL; j++) /* loop over cols */
printf ("%2d", matrix[i][j]); /* outputting values */
putchar ('\n'); /* tidy up with newline */
}
return 0;
}
Example Input File
$ cat dat/matcoords.txt
2,3 4 3 1
3,1 3 2 2
1,4 1 2 8
Example Use/Output
$ ./bin/matrix_data_at_coords <dat/matcoords.txt
0 0 0 1 2 8
0 0 4 3 1 0
3 2 2 0 0 0
0 0 0 0 0 0
Look things over and let me know if you have further questions.
footnotes:
1. Note: none of the scanf family provide any error reporting capability beyond succeed/fail. For fine-grained error reporting for numeric conversion, use the strtoX family of functions (e.g. strtol, strtoul, strtod, etc...)
Try this
#include <stdio.h>
#include <stdlib.h>
int main()
{
char string[99];
FILE *data;
int row = 4;
int col = 6;
int y=0;
int matrix[row][col];
int matrixrow,position, s1 , s2 , s3 ;
for (int x = 0; x < row; ++x)
{
for (int y = 0; y < col; ++y)
{
matrix[x][y]=0;
}
}
data=fopen("example.txt" ,"r");
while( fgets( string , 10 , data))
{
// each row we expect int comma int space int space int space int space
// first int is row , int after comma is position , next 3 ints are data to stuff at position
matrixrow =(string[0]- '0')-1; // substract 0 to get int
position=(string[2]- '0')-2;
s1=string[4]- '0';
s2=string[6]- '0';
s3=string[8]- '0';
matrix[matrixrow][position+1]=s1;
matrix[matrixrow][position+2]=s2;
matrix[matrixrow][position+3]=s3;
printf("\n\nfrom text file matrix");
printf("\n%s", string);
printf("\noutput");
printf("[%d]", matrixrow);
for( y=0 ; y<col-1 ; y++)
printf("[%d]", matrix[matrixrow][y]);
}
printf("\n\nPrint whole matrix\n" );
for (int x = 0; x < row; ++x)
{
for (int y = 0; y < col; ++y)
{
printf("[%d]",matrix[x][y]);
}
printf("\n");
}
fclose(data);
}

Displaying output in C

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.

How to resort an array with file input?

I am writing a program that will ask the user for a 'n' value, they will then enter 'n' values that will be stored into an array and sorted. I have this part done easy enough.
I will compare this array with input from a number read from a text file. If the number is bigger than any of the current array values it will replace them and slide the rest down. This creates an array of the largest 'n' values
Example: n = 4 n values are : 999 972 954 462 937
a[4] = {999, 972, 954, 462, 937};
Sorted :
a[4] = {999, 972, 954, 937, 462};
if the file input is say 968 the result is.
Resorted :
a[4] = {999, 972, 968, 937, 937};
This is my current code.
#include <stdio.h>
#include <stdlib.h>
int main(int argc, char *argv[]){
if (argc<3) //error checking
return -1;
int size = atoi(argv[2]);
int a[size];
int i, j, temp=0;
printf("Enter %d numbers\n", size); //user array input for size and n values
for(i = 0; i < size; i++)
scanf("%d", &a[i]);
for(i=0; i < size; i++){ //sorting array
for(j = i+1; j <size; j++){
if( a[i] < a[j]){
temp = a[i];
a[i] = a[j];
a[j] = temp;
}
}
}
FILE *input;
input = fopen(argv[1], "r");
if(input ==NULL) //error checking
return -1;
if(fscanf(input, "%d", &temp) != 1)
return -1;
while(fscanf(input, "%d", &temp) ==1){ //loop while there is file input
for(i =1 < size; i++){ //check if temp is larger than array values
if(temp > a[i] && temp < a[i-1]){
for(j = size-1; j >= i; j--) //slide down the rest of the array
a[j] = a[j-1];
a[i] = temp;
}
}
}
for(i=0; i <size; i++){ //print out array
printf("%d ", a[i]);
}
return (0);
}
I have tried this on a smaller simpler skill were I have already created the array and the values instead of using user input. I also just passed the array check sequence through a loop that increases a number value instead of reading from a file. This seemed to work fine with something like
a[5] = {10, 8, 6, 4, 2};
number = 5; // number++ number = 6 number = 7... until 10
result: a[5] = {10, 9, 8, 7, 6};
I am sad to say that even if the program was not printing the right array at the beginning I could see there were numbers from the file. The loop is still going trough the file, but at one point the output just started being the sorted user array. I can't seem to get the array values right. Any ideas?
Continuing from my comments yesterday, I apologize if the errors were due to the retyping of your code, but that is the whole reason you want to try to cut and paste as Jonathan indicated -- eliminate human error in the transcription process.
I think I understand what your primary problem is. If your goal is to read some number of user input values from stdin, sort them in descending order, and then open a file and read a single additional value into the array in sort-order, then you must provide space for the final value in your array at the time it is declared (if using VLA's). Otherwise, you either need to create a second VLA large enough to store the values from the use and the file, and copy the user provided values to the new array or dynamically allocate the array originally (with malloc or calloc) and then realloc as needed to add space for additional values as required.
In this case, it's not that difficult since you know you are reading one value from the file. Just read the size from the command line argument and then create your array as int a[size + 1];
The rest of your task can be handled in a couple of ways. After you read (and validate) the user input, you can sort your values in descending order, read the value from the file, and create an insert & shuffle routine to insert the value in the correct order and move the remaining array elements down, or (probably a less error prone method) is simply to add the element from the file to the end of the array, and call your sort routine again.
(note: you should get used to using qsort rather than attempting to reinvent the bubble-sort, etc.. It is orders of magnitudes more efficient and much less error prone)
You need limit (or eliminate) your use of atoi as it provides zero error checking. A better approach is to use strtol and then check errno and check the end-pointer against the original to determine if there were any digits read. Below a simple helper function incorporates error-checking for strtol to insure you have an actual value for size.
Further, be careful. While you may expect the user will enter size integer values, there is no guarantee they will. It is better to track the number of values actually entered and use that value in subsequent iterations over the array rather than blindly iterating for (i = 0; i < size; i++) throughout the remainder of your code.
Whether you attempt an insert-in-place of the value read from the file, or just add it to the end of the array and call your sort routine again is up to you. I would encourage you to move your sort code into a function to provide that flexibility without having to duplicate the code in main. Look the following over and let me know if you have any questions. Since I presume this was a homework assignment, the insert-in-place case is shown below (but the simple add the file value to the end and call sort again code is included commented out)
#include <stdio.h>
#include <stdlib.h> /* for strtol */
#include <limits.h> /* for LONG_MAX/MIN */
#include <errno.h> /* for ERANGE,errno */
void sort_int_array_dec (int *a, size_t size);
long xstrtol (char *p, char **ep, int base);
int main (int argc, char **argv) {
/* read size as first argument, or 5 if none given */
int size = argc > 2 ? (int)xstrtol (argv[2], NULL, 10) : 5,
a[size + 1], /* variable length array for user + file values */
n = 0, /* number of values from user */
fval, /* value read from file */
temp, /* temporary value for array */
i = 0;
FILE *fp = NULL;
if (size < 1) return 1;
printf ("enter %d integers\n", size);
while (n < size) { /* read up to size values */
int result, c;
printf (" integer[%2d] : ", n + 1);
/* validate read of each value using scanf return */
if ((result = scanf ("%d", &temp)) != 1) {
if (result == EOF) { /* always check for EOF */
fprintf (stderr, "user canceled input.\n");
break;
}
fprintf (stderr, "error: invalid conversion.\n");
/* empty input buffer of invalid entry */
while ((c = getchar()) != '\n' && c != EOF) {}
}
else /* good value read, save, increment n */
a[n++] = temp;
}
sort_int_array_dec (a, n); /* sort a */
printf ("\nsorted array before inserting value from file:\n\n");
for (int i = 0; i < n; i++)
printf ("a[%2d]: %d\n", i, a[i]);
if (!(fp = fopen (argv[1], "r"))) {
fprintf (stderr, "error: file open failed '%s'\n", argv[1]);
return 1;
}
if (fscanf (fp, "%d", &fval) != 1) { /* read value from file */
fprintf (stderr, "error: read of file value failed.\n");
return 1;
}
printf ("\n value from file: %d\n\n", fval);
/* add fval into array in descending sort order
* (you can add it anywhere and simply call sort again, e.g.)
*/
// a[n] = fval; /* add it to the end of the array */
// sort_int_array_dec (a, n + 1); /* sort a again */
for (i = 1; i < n + 1; i++) {
if (fval > a[i-1]) {
temp = a[i-1];
a[i-1] = fval;
break; /* temp now holds value to insert at i */
}
}
if (i == n + 1) /* if already at last element just set it */
a[n] = fval;
else /* otherwise, insert and shuffle remaining elements down */
for (int j = i; j < n + 1; j++) {
int mov = a[j];
a[j] = temp;
temp = mov;
}
printf ("sorted array after inserting value from file:\n\n");
for (int i = 0; i < n + 1; i++)
printf (" a[%2d]: %d\n", i, a[i]);
return 0;
}
/** sort integer array descending (your code) */
void sort_int_array_dec (int *a, size_t size)
{
size_t i, j;
int temp;
if (size < 2) return; /* nothing to sort */
for (i = 0; i < size; i++) {
for (j = i + 1; j < size; j++) {
if (a[i] < a[j]) {
temp = a[i];
a[i] = a[j];
a[j] = temp;
}
}
}
}
/** a simple strtol implementation with error checking.
* any failed conversion will cause program exit. Adjust
* response to failed conversion as required.
*/
long xstrtol (char *p, char **ep, int base)
{
errno = 0;
char *endpt = ep ? *ep : NULL;
long tmp = strtol (p, &endpt, base);
/* Check for various possible errors */
if ((errno == ERANGE && (tmp == LONG_MIN || tmp == LONG_MAX)) ||
(errno != 0 && tmp == 0)) {
perror ("strtol");
exit (EXIT_FAILURE);
}
if (endpt == p) {
fprintf (stderr, "No digits were found\n");
exit (EXIT_FAILURE);
}
if (ep) *ep = endpt;
return tmp;
}
Example Use/Output
$ cat dat/file.txt
523
$ ./bin/addintoarray dat/file.txt 4
enter 4 integers
integer[ 1] : 400
integer[ 2] : 500
integer[ 3] : 600
integer[ 4] : 700
sorted array before inserting value from file:
a[ 0]: 700
a[ 1]: 600
a[ 2]: 500
a[ 3]: 400
value from file: 523
sorted array after inserting value from file:
a[ 0]: 700
a[ 1]: 600
a[ 2]: 523
a[ 3]: 500
a[ 4]: 400
/*I'm a beginner C programmer so I don't know much of the syntax.
But I think I can help you with that problem.
I created a simple code and I hope I can really help
the integers from the file must be already sorted.
So the only integer that we will sort is the recent integer that the user inputed.
*/
/*So here's my code of sorting array of integers coming from file.
Please give it a try.
It's not the same syntax as your code but I know you can see my point*/
#include <stdio.h>
#include <stdlib.h>
//my style here is I'm declaring the max Num that I want to put in array.
//But you can do this with different style.
#define MAX_ARRAY 10
//I created separate functions
void readFile(int num_arr[]);
void sortArray(int num_arr[]);
void writeFile(int num_arr[]);
int main()
{
int num_arr[MAX_ARRAY + 1]; // take note that I added 1 (one). And you will see later why I did that
readFile(num_arr);
sortArray(num_arr);
writeFile(num_arr);
//Now we can sort them. Use a temp_num holder.
return 0;
}
void readFile(int num_arr[])
{
int x = 0;
int y = 0;
int temp_num;
FILE *sample_file_pointer = fopen("sample_file.txt", "r");
//first I read the integers from the file and put them in int array.
while(fscanf(sample_file_pointer, " %d\n", &num_arr[x]) == 1)
{
x++;
}//after reading the integers, the last element of the array we declared is still unused.. Now we will use it.
fclose(sample_file_pointer);
//now we will use the unused element by entering the 'n'. Then we will sort the array later.
printf("Enter value of n: ");
scanf(" %d", &num_arr[MAX_ARRAY]);//We put the n value in the last element of the array
}
void sortArray(int num_arr[])
{
int x = MAX_ARRAY;//We will use this to point the last element of the array.
int temp_num;
/*because the array from
the file is already
sorted, (I know you can
do the sorting of that.
That's why I didn't include
it here to make this short)
we can just test the most recent
integer that is added by the user*/
//We do that with this loop
for(int i = MAX_ARRAY; i > 0; i--)
{
if(num_arr[x] >= num_arr[i - 1])
{
temp_num = num_arr[x];
num_arr[x] = num_arr[i - 1];
num_arr[i - 1] = temp_num;
//now set the x to the swapped element to follow the recent number all through. Till the element test becomes 1.
x = i - 1;
}
}
//now we're ready to write this sorted array to a file again
}
void writeFile(int num_arr[])
{
FILE *sample_file_pointer = fopen("sample_file.txt", "w");
for(int i = 0; i < MAX_ARRAY; i++)
{
fprintf(sample_file_pointer, "%d\n", num_arr[i]);
}
//We can ignore the last element of the array. She's out of the group now. It's her fault for being the lowest.. LOL..
fclose(sample_file_pointer);
}

Read integers from file in C

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.

Resources