Problem scanning a string from a text file into an array - c

Let's say I have a simple words.txt file that has contents like this:
house
car
horse
So I want to scan those words into an array so it would be words[0] would be house, words[1] would be car etc.. So I am having this problem that it seems I am having an infinite while loop, why is that? And am I scanning the words properly?
#include <stdio.h>
#include <stdlib.h>
#define MAX_WORDS 10
int main() {
FILE *f;
f = fopen("words.txt", "r");
char words[MAX_WORDS];
int i = 0;
while(1) {
fscanf(f, "%s", &words[i]);
if(feof(f)) {
break;
}
i++;
}
fclose(f);
return 0;
}

Your array can hold 1 word or n series of characters. What you want is an array of strings. First dimension must have MAX_WORD size and 2nd MAX_WORD_LEN size.
#include <stdio.h>
#include <stdlib.h>
#define MAX_WORDS 10
#define MAX_LEN 51
int main() {
FILE *f;
f = fopen("words.txt", "r");
char words[MAX_WORDS][MAX_LEN]; /* Can hold MAX_WORDS string of MAX_LEN chars */
int i = 0;
while(1) {
fscanf(f, "%50s", words[i]);
if(feof(f) || i == MAX_WORDS - 1) {
break;
}
i++;
}
fclose(f);
return 0;
}

First, you should think about the array storing the strings. Remember that strings are arrays by them selves. When you know the maximal length of the words it is easy to define this array of char arrays:
#define MAX_WORD_LEN 32
char words[MAX_WORDS][MAX_WORD_LEN];
Then you can read each string like this
fscanf(f, "%s", words[i]);
Note: your code can lead to buffer overflows, because you do not have a check for the variable i and "%s" is considered insecure (like gets), because it assumes that the read string fits into the buffer. Do not use these if possible, otherwise use these only, when you trust the input: Never: scanf("%s", ...); or gets(...)
If you know the width, you can use it with scanf as the following:
char str[11];
scanf("%10s", str); // one less than the buffer size

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 to store STDIN from text file

I need to read in words from a text file and then count the occurrences of each word but I can't figure out how to store the words in a variable.
I read the code in using fgets, and then i can print it using printf. However when I try to store the character array in a different array that I can use to compare the character arrays later, i keep getting seg faults. How can I go about saving the character array "line" in a different array?
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#define MAXSIZE 500
#define MAXWORDS 1000
int main ( int argc, char *argv[] ) {
char line[MAXSIZE];
char line1[MAXWORDS][MAXSIZE];
int i,j,k;
int count = 0;
while ( fgets ( line, MAXSIZE, stdin ) != NULL ) {
printf("%s", line);
strcpy(line1[count], line);
printf("%s\n", line1[count][i]);
count++;
}
return(0);
}
(This is my updated code, it still prints the first line and then seg faults.)
when I compile and run this code, it prints the first line of the text file and then returns "segmentation fault"
Perhaps the question code is close.
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#define MAXSIZE 500
#define MAXWORDS 1000
int main(int argc, char *argv[])
{
char line[MAXSIZE];
char line1[MAXWORDS][MAXSIZE];
int count = 0;
while(fgets(line, MAXSIZE, stdin))
{
printf("%s", line);
strcpy(line1[count], line);
printf("%s\n", line1[count]); // instead of: printf("%s\n", line1[count][i]);
count++;
}
return(0);
}
Your strcpy works as it should, but the printf caused a warning already at compile time, change the printf-line from printf("%s\n", line1[count]); to printf("%s\n", line1[count]);
After the while loop you can verify your copy with:
for (int i=0; i < count; i++){
printf("%d: %s",i, line[i]);
}
Although fgets will put a terminating 0-byte at the end of the buffer, it would be more defensive to user strncpy which is guaranteed not copy more than n-bytes, but in this example you could eliminate the copy altogether by writing directly in to line[count] buffer.
Also you shod take care and stop reading before overwriting your buffers.
When you call fgets you limit the read to MAXSIZE which is good but you should also check count is below MAXWORDS

Weird characters when printing out strings in an array?

I'm currently working on a program that reads strings from a file and stores them into a 2-D array. However, when I try to print out the contents of the array, I get a random character every time. Here is my code:
#include <stddef.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int main(){
FILE* file_pointer;
char user_input[80];
char line[81];
char all_lines_array[100][81];
int total_lines = 0;
while (1){
printf("Please enter a command: ");
scanf("%s", &user_input);
if (strstr(user_input, "read") != NULL){
file_pointer = fopen("C:\\Users\\Tyler\\Desktop\\Hello.txt","r");
while (fgets(line, 100, file_pointer)) {
line[strlen(line)+1] = "\0";
*all_lines_array[total_lines] = line; //My guess is this is wrong
total_lines++;
}
fclose(file_pointer);
}
}
return 0;
}
I suspect that this is because I'm incorrectly inserting string into my 2-D array, but I have no idea what it is I'm doing wrong. I've set the numbers so that there can only be a maximum of 100 lines in a file, and each line can only be 80 characters long (with the "\0" at the end).
Here is my input file:
John Doe 1221 Washington St. 1234567
Jane Doe 1233 Washington St. 1234568
Cain Doe 1234 Washington St. 1234569
There where some statements flagged when compiling with -Wall [which I always recommend doing], which may have helped with some of the errors.
Here's the corrected version, annotated with comments [please pardon the gratuitous style cleanup]:
#include <stddef.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int
main()
{
FILE *file_pointer;
char user_input[80];
char line[81];
char all_lines_array[100][81];
int total_lines = 0;
while (1) {
printf("Please enter a command: ");
// compiler flagged this with a warning
#if 0
scanf("%s", &user_input);
#else
scanf("%s", user_input);
#endif
if (strstr(user_input, "read") != NULL) {
#ifndef CRAIG
file_pointer = fopen("C:\\Users\\Tyler\\Desktop\\Hello.txt", "r");
#else
file_pointer = fopen("input.txt", "r");
#endif
if (file_pointer == NULL) {
printf("file not found\n");
continue;
}
// NOTE: using sizeof here is better as 100 was specified but
// "line" was only 81
while (fgets(line, sizeof(line), file_pointer)) {
// NOTE: I presume this is to strip the newline
// in the original form, it would add garbage chars to the end
// [because of "\0" instead of '\0']
#if 0
line[strlen(line) + 1] = "\0";
#else
line[strlen(line) - 1] = 0;
#endif
// NOTE: the compiler flagged this as well
#if 0
*all_lines_array[total_lines] = line; // My guess is this is wrong
#else
strcpy(all_lines_array[total_lines],line);
#endif
total_lines++;
}
fclose(file_pointer);
}
}
return 0;
}
fgets is reading 100 chars but your static allocated variable char line[81] is only allocates memory for 81 chars.
instead of the = operator use strcpy

fgets segmentation fault when reading input from user

here's the offending code using ubuntu
char *name;
int main(void)
{
fgets(name, sizeof(name), stdin);
}
void HUD()
{
printf("%s ", name);
}
Here's my problem. I started with scanf("%s", &name) and was getting junk at the end of the string. Through the last 2 hours have been reading docs on scanf, and fgets, because apparently scanf shouldn't be used when you don't know the size of the array you want, (and since user input can vary in size) I decided to try using fgets. I've also tried setting a fixed value both by char name[100]; and by fgets(name, 100, stdin)
Now I'm getting a segmentation fault, and through reading every result I found on the first 2 pages of google, my syntax appears correct, and I've found nothing on cboard or here to fix my problem.
Any ideas?
sizeof(name) Will be the size of the pointer on your system, on mine it's 8 bytes. Not the size of the buffer, as you might have been expecting
Also char* name is uninitialised. You will try to write to an uninitialised buffer and it will end in undefined behaviour.
To resolve either make it a fixed size buffer or allocate some space on the heap.
Allocate
#include <stdio.h>
#include <stdlib.h>
#define NAME_SIZE 100
char *name;
void HUD()
{
printf("%s ", name);
}
int main(void)
{
name=calloc(NAME_SIZE, sizeof(char));
fgets(name, NAME_SIZE, stdin);
HUD();
free(name);
}
Static Array
#include <stdio.h>
#include <stdlib.h>
#define NAME_SIZE 100
char name[NAME_SIZE];
void HUD()
{
printf("%s ", name);
}
int main(void)
{
fgets(name, NAME_SIZE, stdin);
HUD();
}
You must pass the size of the buffer to fgets so it know how much space it has to write in to.
char *fgets(char *restrict s, int n, FILE *restrict stream);
The fgets() function shall read bytes from stream into the array
pointed to by s, until n-1 bytes are read, or a is read and
transferred to s, or an end-of-file condition is encountered. The
string is then terminated with a null byte. [0]
You need to allocate it to a specific size and call fgets with that size. This code can help you accomplish the same thing, but it has a fixed size buffer.
#include <stdlib.h>
#include <stdio.h>
char name;
char* buffer;
int buffer_size = 16;
int i = 0;
void HUD()
{
printf("%s ", buffer);
}
int main(void)
{
buffer = malloc(buffer_size);
if(!buffer) return;
for(;;) {
name = getchar();
if(name < 0) {
buffer[i] = '\0';
goto finish;
} else if(i < (buffer_size -1)) {
buffer[i++] = name;
} else if(name == '\n') {
break;
}
}
buffer[i] = '\0';
finish:
HUD();
free(buffer);
return 0;
}
[0] http://pubs.opengroup.org/onlinepubs/009695399/functions/fgets.html

Reading a text file into 2d array

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.

Resources