Reading a text file into 2d array - c

I have a text file with just random letters in rows and columns. All I would like to do is make a 2d array so that it's puzzle[i][j] where if I put printf("%c", puzzle[5][4]); it would simply give me the 4th row and 3rd columns character (since it starts at 0 in an array). Here is my code so far.
#define MAXROWS 60
#define MAXCOLS 60
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <math.h>
main()
{
FILE *TableFilePtr;
char TableFileName[100];
char PuzzleFileName[100];
char puzzle[MAXROWS][MAXCOLS];
printf("Please enter the table file name: ");
scanf("%s",TableFileName);
TableFilePtr=fopen(TableFileName, "r");
if(TableFilePtr == NULL)
{
printf("Can't open %s", TableFileName);
exit(EXIT_FAILURE);
}
char words;
int n;
n=0;
int i,j,row,col;
int rowcount, colcount;
printf("\n how many rows and colums are there? separate by a space: ");
scanf("%d %d",&row, &col);
/* while(fscanf(TableFilePtr,"%c",&words)!= EOF)
{
printf("%c",words);
}
*/
/*for (colcount=0;colcount<col;colcount++)
{
for (rowcount=0;rowcount<row;rowcount++)
{
printf("%c ",words);
}
printf("\n");
}
*/
for(i=0;i<row;i++){
for(j=0;j<col;j++){
fscanf(TableFilePtr, "%c %s\n",&puzzle[i]][j]);
//puzzle[i][j]=words;
// printf("%c ", puzzle[i][j]);
}
printf("\n");
}
}
The commented area at the end (just the starting part) works to simply print out the text file in the compiler. I would like to get it to be in a 2d array though.
for(colcount=0;colcount<col;colcount++){...}

I would do something like this (I didn't use all of your exact variable names but you get the idea):
char puzzle[MAXROWS][MAXCOLS], line[MAXCOLS];
FILE *infile;
int cols = 0, rows=0;
/* ... */
infile = fopen(TableFileName, "r");
while(fgets(line, sizeof line, infile) != NULL)
{
for(cols=0; cols<(strlen(line)-1); ++cols)
{
puzzle[rows][cols] = line[cols];
}
/* I'd give myself enough room in the 2d array for a NULL char in
the last col of every row. You can check for it later to make sure
you're not going out of bounds. You could also
printf("%s\n", puzzle[row]); to print an entire row */
puzzle[rows][cols] = '\0';
++rows;
}
Edit: much shorter version will have newline and NULL chars at the end of each row unless you manually pick them off. You may have to tweak puzzle[][] (use MAXCOLS +/- n or some such) to make it work for you.
for(c=0; c<MAXROWS; ++c){
fgets(puzzle[rows], sizeof puzzle[rows], infile);
}
At the end of the loop, puzzle[x][y] should be a 2d array of chars from your input file. Hope that helps.

Related

C read file content into an array of strings

I need to load the contents of a file into two string arrays. I tried the following and it is not working.
file.txt contains 10 records and each record has two string values separated by whitespace.
CODE:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int main(void) {
char line[12][20];
FILE *fptr = NULL;
int i = 0;
int tot = 0;
fptr = fopen("file.txt", "r");
char arr[20][20];
while (fgets(line, sizeof(line), fptr)) {
strcpy(arr[i],line);
i++;
}
tot=i;
for (int i=0; i<tot; i++) {
printf("first value %s",arr[i][0]);
printf("second value is %s",arr[i][1]);
printf("\n");
}
return 0;
}
If I understand correctly, you're trying to store data in a structure like:
{{"line1A", "line1B"}, {"line2A", "line2B"}, {"line3A", "line3B"}}
It looks like you need an array where each element consists of two arrays (strings), one for the first value and one for the second value on each line. If this is the case, you need a three dimensional array of chars.
In the example below I've declared arrayOfLines as array with 12 elements each of which has 2 arrays of chars (for your two values per line), with space for 20 chars in each string (NULL terminated char array)
There are some other problems with your code:
The first parameter for fgets() should be a char * - a pointer to a string buffer. Your code passes in a multi-dimensional array of chars.
Your while loop should continue until fgets returns NULL
You need to split each line into multiple strings
Check for buffer overruns when copying strings with strcpy()
In the example code I used strtok() delimited by a " " space character - you may need to play around with this - strtok can accept an array of chars to be used as a delimiter. In the example, I split the first string using the first space char, and the second string is delimited by the end of line.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int main(void)
{
// Array for 12 lines, each with 2 strings, each string max 20 chars
// Adjust values as required.
char arrayOfLines[12][2][20];
FILE *fptr = NULL;
int i = 0;
int tot = 0;
fptr = fopen("file.txt", "r");
// char arr[20][20]; not needed
char line[20];
while(fgets(line, sizeof(line) / sizeof(line[0]), fptr) != NULL)
{
// Rudimentary error checking - if the string has no newline
// there wasn't enough space in line
if (strchr(line, '\n') == NULL) {
printf("Line too long...");
return EXIT_FAILURE;
}
// Split string into tokens
// NB: Check for buffer overruns when copying strings
char *ptr1 = strtok(line, " ");
strcpy(arrayOfLines[i][0], ptr1);
char *ptr2 = strtok(NULL, "\n");
strcpy(arrayOfLines[i][1], ptr2);
i++;
}
tot=i; // Unecessary - just use a different variable in your loop and use i as the upper bound
for (int i=0;i<tot;i++)
{
printf("first value %s\n", arrayOfLines[i][0]);
printf("second value is %s\n", arrayOfLines[i][1]);
printf("\n");
}
return 0;
}
printf("first value %s",arr[i][0]);
printf("second value is %s",arr[i][1]);
Basicly all you are doing is printing 2 chars from i word when you want to print full string you should do it like this: printf("%s",arr[i]); You said that value is separated by whitespace so when you are getting line from file you will save it to arr[i] (if first line in file contains "Hello World", your arr[0] will contain "Hello World") when you want to split it into 2 printf you need to print them char by char until space.
Edit: I reminded myself about function sscanf you can use it to get data from file array like you whould do it with keyboard input
You can use this to do that
Code
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
int main(void){
char line[12][20];
char arr[20][20];
FILE *fptr=NULL;
int i=0;
fptr = fopen("file.txt", "r");
if(!fptr){
printf("cant open file\n");
exit(1);
}
while(fgets(*line, sizeof(line), fptr)){
strncpy(arr[i],*line, sizeof(*line));
i++;
}
for (int j=0;j<i;j++){
printf("%s\n", arr[j]);
}
return 0;
}
Notes and changes I made on your code:
Check fptr as return value of open() if it's NULL decide what to do.
Remove unnecessary tot variable and use another index j in last for loop.
Use strncpy() as a better version of strcpy()
Correct way of print arr, printf("%s\n", arr[j]);
\n can be embed on first printf()

How do I use fgets along with malloc to create an array of strings?

I am taking in a variable amount of lines of string using fgets. The end of each line is marked by a new line. I am trying to allocate an array of strings (using malloc). Each index of the array will point to each line of the text that is entered from the user. This was really tough to explain so here is an example:
Using fgets and malloc, allow the user to enter multiple lines of strings. The user will signal the end of the strings with a '.' on a newline. Each line of the multiple strings will be stored as a string in a dynamically allocated array. The output of the program must print each line in reverse order.
Ex:
Enter string:
(this is sample input)
The sky is blue
The grass is green
I love life
.
(this should be the output)
I love life
The grass is green
The sky is blue
I have this so far:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int main()
{
char charsOnLine[1000];
char **poem;
int i;
int j;
fgets(charsOnLine, 1000, stdin); //runs only once
while (charsOnLine[0] != '.')
{
poem = malloc(sizeof(char*) * 3);
for(j = 0; j < strlen(charsOnLine); j++)
{
poem[j] = malloc(sizeof(strlen(charsOnLine)));
strcpy(poem[j], charsOnLine);
}
fgets(charsOnLine, 1000, stdin);
}
for (j = 0; j < strlen(*poem); j++) //test to print each line of the poem (not in reverse)
{
printf("%s\n",poem[j]);
}
return 0;
}
I am have just started with double pointers, pointers, dynamically allocating memory, fgets() and putting them all together is giving me some trouble.
In my code, I'm testing to see if it'll print each line I enter the same way I entered it, but it is printing the last entered string 4 times instead of each different line.
Once I figure out how to print each entered line, I will figure out how to print them backwards.
There's a rather simple solution to your "in reverse order" problem, which does not even require dynamic memory allocation but just recursion:
void readRecursive() {
char charsOnLine[1000];
if (fgets(charsOnLine, 1000, stdin) && charsOnLine[0] != '.') {
readRecursive();
}
fputs(charsOnLine, stdout);
}
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int main()
{
char charsOnLine[1000];
char **poem = NULL;
size_t size = 0, current;
while (fgets(charsOnLine, 1000, stdin) != NULL && charsOnLine[0] != '.')
{
char **tmp;
tmp = realloc(poem, (size + 1) * sizeof(*poem));
if(tmp)
{
poem = tmp;
poem[size] = malloc(strlen(charsOnLine) + 1);
if(poem[size])
{
strcpy(poem[size++], charsOnLine);
}
}
}
current = size;
while(current--)
{
fputs(poem[current], stdout);
}
/* do something more with your read poem */
return 0;
}

Detecting single character in string

So, I'm trying to detect a single character in a string. There must be no other characters besides whitespace and a null character. This is my first issue, as my code detects the character in a string with other characters (besides the whitespace).
My second issue, is I can't seem to figure out how best to read matrices from a file. I'm supposed to read the first line and get the ROWS x COLUMNS. Then I'm supposed to read the data into the a matrix array that is stored globally. Then reading the second matrix into a second matrix array (stored globally as well).
#include <stdio.h>
#include <stdlib.h>
#include <pthread.h>
#include <string.h>
#define MAXLINE 100
typedef struct matrixStruct{
int rows;
int columns;
}matrixStruct;
typedef int bool;
enum{
false,
true
};
/*
*
*/
int aMatrix1[10][10];
int aMatrix2[10][10];
int multiMatrix[10][10];
int main(int argc, char** argv){
FILE *inputFile;
char tempLine[MAXLINE], *tempChar, *tempString;
char *endChar;
endChar = (char *)malloc(sizeof(char));
(*endChar) = '*';
bool readFile = true;
inputFile = fopen(argv[1], "r");
if(inputFile == NULL){
printf("File %s not found.\n", argv[1]);
perror("Error");
exit(EXIT_FAILURE);
}else{
printf("File opened!\n");
}
int numRow, numColumn, i, j, tempNum, count = 0;
do{
fgets(tempLine, MAXLINE, inputFile);
tempChar = strchr(tempLine, '*');
if(tempChar != NULL){
printf("True # %s\ncount=%d\n",tempChar,count);
readFile = false;
}else{
sscanf(tempLine, "%d %d", &numRow, &numColumn);
count++;
for(i=0;i<numRow;i++){
fgets(tempLine, MAXLINE, inputFile);
for(j=0;j<numColumn;j++){
aMatrix1[i][j] = atoi(tempNum);
}
}
}
}
while(readFile);
printf("aMatrix1[%d][%d]= \n", numRow, numColumn);
for(i=0; i < numRow;i++){
for(j=0; j < numColumn; j++){
printf("aMatrix[%d][%d] = %d\t", i, j, aMatrix1[i][j]);
}
printf("\n");
}
return (EXIT_SUCCESS);
}
For the first issue you could do what you suggested in your comment (regexp are an overkill here) - loop through the string, break on any non-whitespace char that's not what you expect, and count the ones that do match - you don't want 0 matches, and i guess also no more than 1.
However, I suggest you read the man page for strtok - I normally wouldn't suggest it as it's not thread-safe and has strange behaviors, but in this simple case it could work fine - provide whitespace chars as delimiters, and it would return the first non-whitespace string. If that's doesn't strcmp with "*", or if the next call to strtok doesn't return null, then it's not a match.
By the way - what do you plan to do with lines that aren't " .. * .. " or " ROWS x COLUMNS "? you're not handling them right now.
As for the second issue - strtok again could come to the rescue - repeated calls would just give you the whitespace-delimited numbers (as strings), and you'll be able to populate tempNum for each iteration.

C language, How to fix the segmentation fault

Here is my code so far
#define MAXROWS 60
#define MAXCOLS 60
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <math.h>
main()
{
char TableFileName[100];
char PuzzleFileName[100];
char puzzle[MAXROWS][MAXCOLS];
char line[MAXCOLS];
FILE *TableFilePtr;
int cols;
int rows;
cols=0;
rows=0;
printf("Please enter the table file name: ");
scanf("%s",TableFileName);
/* ... */
TableFilePtr = fopen(TableFileName, "r");
//printf("\n how many rows and colums are there? separate by a space: ");
// scanf("%d %d",&rows, &cols);
while(fgets(line, sizeof line, TableFilePtr) != NULL)
{
for(cols=0; cols<(strlen(line)-1); ++cols)
{
puzzle[rows][cols] = line[cols];
}
/* I'd give myself enough room in the 2d array for a NULL char in
the last col of every row. You can check for it later to make sure
you're not going out of bounds. You could also
printf("%s\n", puzzle[row]); to print an entire row */
puzzle[rows][cols] = '\0';
++rows;
}
/*int c;
for(c=0; c<MAXROWS; ++c){
fgets(puzzle[rows], sizeof puzzle[rows], TableFilePtr);
}*/
printf("%s",puzzle[5][5]);
}
what i would like to do is make it so it reads from a text file which contains a wordsearch in a txt file so that it has just random letters. i would like to be able to make it so that i am able to say puzzle[5][5] and it gives me the character in the 4th row and 4th column. I am running into a segmentation fault and i do not know how to fix it though.
You are trying to print a string with printf("%s", puzzle[rows][cols]) and giving a char puzzle[rows][cols] is 1 character and not a string.
do this: printf("%c", puzzle[rows][cols]); instead.
char puzzle[MAXROWS][MAXCOLS];
char line[MAXCOLS];
//...
while(fgets(line, sizeof line, TableFilePtr) != NULL)
{
for(cols=0; cols<(strlen(line)-1); ++cols)
{
puzzle[rows][cols] = line[cols];
}
puzzle[rows][cols] = '\0';
++rows;
}
This is dangerous because you never check that the number of lines is less than MAXROWS or that the length of each line is less than MAXCOLS. That means that a malformed data file can cause you to write beyond the bounds of the puzzle array, which can cause a segmentation fault, corrupted memory, or other problems.
To fix, you need to include limits in the loop conditions, like this:
while (frets(line, sizeof line, TableFilePtr) != NULL && rows < MAXROWS) {
for (cols=0; cols<(strlen(line)-1) && cols < MAXCOLS; ++cols) {
//...
I didn't see obvious errors except you didn't check the boundary of puzzle array when you write chars into it. so I think maybe a possible reason is your input file is too large to fit into puzzle array then the array has been overflowed.

Know the row with max characters (C)

I have written a program in C, to find the row with the max number of characters.
Here is the code:
#include <stdio.h>
#include <stdlib.h>
#include <ctype.h>
#include <string.h>
int main (int argc, char *argv[])
{
char c; /* used to store the character with getc */
int c_tot = 0, c_rig = 0, c_max = 0; /* counters of characters*/
int r_tot = 0; /* counters of rows */
FILE *fptr;
fptr = fopen(argv[1], "r");
if (fptr == NULL || argc != 2)
{
printf ("Error opening the file %s\n'", argv[1]);
exit(EXIT_FAILURE);
}
while ( (c = getc(fptr)) != EOF)
{
if (c != ' ' && c != '\n')
{
c_tot++;
c_rig++;
}
if (c == '\n')
{
r_tot++;
if (c_rig > c_max)
c_max = c_rig;
c_rig = 0;
}
}
printf ("Total rows: %d\n", r_tot);
printf ("Total characters: %d\n", c_tot);
printf ("Total characters in a row: %d\n", c_max);
printf ("Average number of characters on a row: %d\n", (c_tot/r_tot));
printf ("The row with max characters is: %s\n", ??????)
return 0;
}
I can easily find the row with the highest number of characters but how can I print that out?
You'll need to store the line with the highest character count, e.g. in an array.
If you can make assumptions about line length, declare two arrays of characters:
char currentLine[255];
char maxLine[255];
Upon reading each character with getc, put it in the line array. After processing the line, if the current line has a higher count, copy the contents of currentLine into maxLine, using memcpy. You're already keeping track of the lengths for those two arrays as c_tot and c_max.
And if you can't make assumptions about line length, you can use the same technique but you'll need to malloc and realloc your buffers as you encounter lines longer than your initial size.
You should store the current row as well in a char * and have a largest string char *. In the test where you determine the max size, you should also copy the current row to the largest string.
Don't forget to initialize the largest string to "" in order to avoid an error at the zero length file situation.

Resources