Issues with reading words from a text file into 2d Array - c

I recently started a program in which I have to sort a list of guests, but the overall problem details are irreverent for the issue I'm having.
Well, I want to scan in first and last names from a file SEPARATELY, which I know you do by scanning them as strings. However, we just started using strings and I'm having a little brain fart and I've searched places but I can't figure out how to do so. I'm also having trouble structuring the array inside the for loops. My mind has been totally out of school since Skyrim came out :). Here's the input text file:
//First number is the amount of families on the list, second number is the room capacity, ignore that for now.
10 30
//Format = First Name, Last Name, Number of Family Members (ignore), Priority Level (ignore)
BEN JOHNSON 4 2
DOUG ESPINOSA 3 2
SARAH TELLINGER 5 3
GRANT THOMPSON 5 2
JENNIFER WEST 7 6
JACKSON JOHNSON 1 5
MARTY MCFLY 4 1
ELIZABETH JAMES 2 6
MICKEY MOUSE 2 4
RAJ SHAH 2 5
Here's my code so far: Assume MAX_FAMILY_MEMBERS = 10 and MAX_NAME_LENGTH = 20
void Read_First_Name(FILE *ifp, char First_Name[//Assume MAX_FAMILY_MEMBERS is here][MAX_NAME_LENGTH]){
int i, j;
for(i = 0; i < MAX_FAMILY_MEMBERS; i++)
{
for(j = 0; j < MAX_NAME_LENGTH; i++)
{
fscanf("%s", First_Name[i][j]);
}
}}
I'm sure this is most likely wrong but I'm quite confused and out of it. If there are any questions about my program please ask.

Its easy if you use fgets with sscanf in one loop like
char line[100], firstnames[100][100], famnames[100][100];
int counter=0;
while( fgets(line,100,yourfilepointer) )
if( sscanf(line,"%s%s",firstnames[counter],famnames[counter])==2 )
++counter;
...
while( counter-- )
printf("%s %s\n",firstnames[counter],famnames[counter]);

void Read_And_Store(FILE *ifp, int FAMILIES_KNOWN, char First_Name[][MAX_NAME_LENGTH], char Last_Name[][MAX_NAME_LENGTH], int Family_Members[], int Priority[]){
int i;
for(i = 0; i < FAMILIES_KNOWN - 1; i++)
{
fscanf(ifp, "%s", First_Name[i]);
fscanf(ifp, "%s", Last_Name[i]);
fscanf(ifp, "%d", &Family_Members[i]);
fscanf(ifp, "%d", &Priority[i]);
}}
Here's what I did and it works fine when I print it out. However, I've tried a bunch of stuff trying to sort the printed list by priority level, but none of them are successful... any ideas? After I get the sort down the rest is just basic logic and swapping.

I Presume you want to sort the families basing on their priority level. In the code you wrote,
Your fscanf syntax is incorrect. Go through the syntax once more.
for(i = 0; i < MAX_FAMILY_MEMBERS; i++)
{
for(j = 0; j < MAX_NAME_LENGTH; i++)
{
fscanf("%s", First_Name[i][j]);
}
}
It is good that you want to read line by line (family by family) but how you read each family is improper.
%s format specifier reads an entire string until it encounters a space.
so that second for loop is very messy.
I will slightly change the code, you can improve on it and write your own logic
#define NUMBEROFFAMILIES 10
#define FAMILYNAMELENGTH 20
char firstName[NUMBEROFFAMILIES][FAMILYNAMELENGTH]; // to store first name
char secondName[NUMBEROFFAMILIES][FAMILYNAMELENGTH]; // to store second name
int familtyPriority[NUMBEROFFAMILIES][1]; // to store priority
int i, j;
for(i = 0; i < MAX_FAMILY_MEMBERS; i++){
fscanf(ifp,"%s",firstName[NUMBEROFFAMILIES]); // read first name
fscanf(ifp,"%s",secondName[NUMBEROFFAMILIES]); // read second name
fscanf(ifp,"%d", &j); // Ignore family members count
fscanf(ifp,"%d", &familtyPriority[NUMBEROFFAMILIES][1]); // family priority
}
EDITED FOR THE NEXT QUESTION
You want to sort based on the priority level.
int familtyPriorityCopy[NUMBEROFFAMILIES][1]; // to store priority
int familyOrder[NUMBEROFFAMILIES][1]; // to store the proper order.
// initialize them
for (i=0;i<NUMBEROFFAMILIES;i++){
familtyPriorityCopy[i][1] = familtyPriority[i][1];
familyOrder[i][1] = i;
}
// sorting [insertion sort]
for (i=1;i<NUMBEROFFAMILIES;i++){
for (j=0;j<i;j++){
if (familtyPriorityCopy[j][1] < familtyPriorityCopy[i][1]){
swap(familtyPriorityCopy[i][1],familtyPriorityCopy[j][1]);
swap(familyOrder[i][1], familyOrder[j][1]);
}
}
}
At the end, familtyPriorityCopy array is sorted. But this is not what is important. familyOrder array is what points to the correct order. We will use this array to print them in the right order.
for(i = 0; i < MAX_FAMILY_MEMBERS; i++){
printf("%s",firstName[familyOrder[i][1]][1]); // read first name
printf("%s",secondName[familyOrder[i][1]][1]); // read second name
printf("%d", familtyPriority[familyOrder[i][1]][1]); // family priority
}

Related

Redirecting a file from stdin, using fgets() to read information to array

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.

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.

Get a certain number of elements into an Array

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;
}

Concatenating two 2d char arrays

I wrote a small program to combine two 2d arrays. Here is the code:
#define MAX 7
int main(void) {
int i, j;
char *array1[] = {"Welt,", "bist", "du"};
char *array2[] = {"noch", "zu", "retten?"};
char final[MAX][MAX];
for(i = 0; i < 3; i++) {
// initialize ith names element with first name
strcpy(final[i], array1[i]);
}
for(j = 0; j < 3; j++) {
// concatenate the last name to the firstname+space string
strcat(final[i], array2[j]);
}
for (i = 0; i != 6; i++) {
printf("%s", final[i]);
}
return EXIT_SUCCESS;
}
I get really strange output like:
Welt,bistbistdunochzuretten?uretten?en?
while what I want is this:
Welt,bistdunochzuretten
As you can see it is not completely wrong. There should not be a space between the words.
How can I fix my code?
The problems were that in the second for you were doing strcat(final[3], array2[j]);, because i was 3 at that point and in the final for you were trying to print from final[0] to final[5], when you only had defined final[0] to final[3] (where on final[0] to final[2] you had the names, and in final[3] you had all the last names concatenated which also exceeded the limit of characters), and without printing them in a new line it was hard to tell which string was what.
Try this.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define MAX 7
int main(void) {
int i,j;
char *array1[] = {"Welt","bist","du"};
char *array2[] = {"noch","zu","retten?"};
char final[MAX][MAX];
for(i=0;i<3;i++)
strcpy(final[i], array1[i]); //To initialize ith names element with first name
for(j=0;j<3;j++)
strcat(final[j],array2[j]); //Concatanate the last name to the firstname+ space string
for (i = 0; i < 3; i++)
printf("%s\n", final[i]);
return EXIT_SUCCESS;
}
There are several problems with your code:
The constant MAX is not large enough for your data. The string "retten?" contains seven characters plus one terminating byte. As such, MAX must be at least 8, otherwise you get undefined behavior.
Your second loop contains uses the wrong index into final[i]. See point 3. for corrected versions.
The use of strcat() is wrong, you should be using strcpy() just like in the first loop. Together with point 2., your second loop should either look like this:
for(j = 0; j < 3; i++, j++) { //add increment for i
strcpy(final[i], array2[j]);
}
or like this:
for(j = 0; j < 3; j++) {
strcpy(final[3 + j], array2[j]); //derive the index from j
}
Regarding Point 1, I always advise against using any compile time constants like MAX. My experience is that these are just bugs that are waiting to strike. Someday, someone will have a use case that exceeds the limit, and your program goes boom. I always allocate buffers to fit the strings that I need to store, leaving the available RAM as the only limit to my code. To this end, functions like strdup() and asprintf() are extremely handy because they already do the allocation for me.
Regarding Point 2, you should try to declare all your loop variables right inside the initialization statement. Like so:
for(int i = 0; i < 3; i++) {
// initialize ith names element with first name
strcpy(final[i], array1[i]);
}
That way you don't run the danger of inadvertently using the loop variable after the loop / forgetting the initialization, etc. because your compiler will complain about the unknown variable.

Reading in a file to create multiple "minesweeper"ish arrays

What I got so far, is a .in file that will create 100 arrays, followed by how many "mines" are on the board, and then 2 numbers for each "mine" representing where they will be placed on the array. This is for my beginner C class, and honestly we've not been taught properly for something this advanced (i say advanced using the term lightly). I know how to read in files, and I know how to create an array, but im unsure how I would read in that many lines, switching from mines to placement over and over again. I also find myself confused as to how to change an array number from 0 to another number based on where a mine is placed.
An example input file:
1
4
1 3
7 5
7 3
3 3
Where the 1 in the first line means we have one board. The 4 on the next line means it will have 4 bombs. The following 4 lines describe the position of the bomb in the array as row column.
Is there anything that anyone can offer me to point me in the right direction?
Below is a partial solution, it leaves a few parts as an exercise for the OP.
#include <stdio.h>
#include <stdlib.h>
#define BOARD_SIZE 8
int main(void) {
FILE *fp;
fp = fopen("mines.in","r");
if ( fp == NULL ) {
fprintf(stderr,"Could not open file\n");
return 1;
}
int nBoards = 0;
int nMines = 0;
int col;
int row;
int currentBoard = 0;
/* We know the first row is going to be the number of boards */
fscanf(fp,"%d",&nBoards);
printf("We have %d boards\n",nBoards);
while ( fscanf(fp,"%d",&nMines) > 0 ) {
int i,j;
/* initialize board as all zeros */
int board[BOARD_SIZE][BOARD_SIZE] = { {0} };
currentBoard++;
printf("Board %d:\n",currentBoard);
/* Read in and set the mines */
for (i=0; i<nMines; i++) {
fscanf(fp,"%d %d",&col,&row);
board[col-1][row-1] = 9;
}
/* Add mine proximity */
for (i=0; i<BOARD_SIZE; i++) {
for (j=0; j<BOARD_SIZE; j++) {
if ( board[i][j] == 9 ) { /* we have a mine */
/* Square to the left */
if (j > 0 && board[i][j-1] != 9) {
board[i][j-1]++;
}
/* Square to the right */
/* Left as exercise for the OP*/
/* Square above */
/* Left as exercise for the OP*/
/* Square below */
/* Left as exercise for the OP*/
}
}
/* Print out the board */
for (i=0; i<BOARD_SIZE; i++) {
for (j=0; j<BOARD_SIZE; j++) {
printf("%d ",board[i][j]);
}
printf("\n");
}
printf("\n");
}
fclose(fp);
if (currentBoard != nBoards) {
fprintf(stderr,"Expected %d boards, read in %d boards\n",nBoards,currentBoard);
return 1;
}
return 0;
}
The code reads in the first line to record the number of boards, then it loops over the blocks of data containing the number of mines and the mine locations. The while loop will perform an fscanf on the lines containing the number of mines, and in the body of the while loop the different mine locations will be read in to the number defined for the board.
Once we have all the mine locations we can calculate the numbers in other squares on the board, only one of which I've shown in the code (others are similar).
Note that the above code does almost no error handling and almost no validation on the input file - if the input file is wrong you could get errors i.e. 'out of range' accesses to arrays. I've left out such checks to make the underlying logic of the program clearer.
Note also that I've assumed that the input indexs are '1'-indexed (i.e. in the range [1,8] rather than '0'-indexed as C expects (i.e. in the range [0,7]), hence the substitution of 1 in the line board[col-1][row-1] = 9;.

Resources