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()
Related
Im trying to print out the strings from a txt file in order.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int main(int argc, char *argv[])
{
// Check for command line args
if (argc != 2)
{
printf("Usage: ./read infile\n");
return 1;
}
// Create buffer to read into
char buffer[7];
// Create array to store plate numbers
char *plates[8];
FILE *infile = fopen(argv[1], "r");
int idx = 0;
while (fread(buffer, 1, 7, infile) == 7)
{
char buffer2[7];
// Replace '\n' with '\0'
buffer[6] = '\0';
strcpy(buffer2, buffer);
// Save plate number in array
plates[idx] = buffer2;
idx++;
}
for (int i = 0; i < 8; i++)
{
printf("%s\n", plates[i]);
}
}
The pasted code just writes one and the same string over and over again, and I cant for the life of me figure out what Im doing wrong. When I debug the "while" method, I see that the buffer updates keep overwriting every entry to the plates array.
In this for loop
while (fread(buffer, 1, 7, infile) == 7)
{
char buffer2[7];
// Replace '\n' with '\0'
buffer[6] = '\0';
strcpy(buffer2, buffer);
// Save plate number in array
plates[idx] = buffer2;
idx++;
}
you declared a local array with automatic storage duration
char buffer2[7];
that will not be alive after exiting the loop. And all elements of the array plates are set by the address of the first element of the array buffer2. That is within the for loop they all point to the same extent of memory.
After exiting the loop the pointers will be invalid.
You need to allocate character arrays dynamically and their addresses to assign to the elements of the array plates.
Also pay attention to that the function fread does not read a string. So this statement
buffer[6] = '\0';
overwrites the last character stored in the array.
Using dynamic allocation should fix your problem. You could try something like this:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int main(int argc, char *argv[])
{
// Check for command line args
if (argc != 2)
{
printf("Usage: ./read infile\n");
return 1;
}
// Create buffer to read into
char buffer[7];
// Create array to store plate numbers
char *plates[8];
FILE *infile = fopen(argv[1], "r");
int idx = 0;
while (fread(buffer, 1, 7, infile) == 7)
{
// Replace '\n' with '\0'
buffer[6] = '\0';
// Save plate number in array
plates[idx] = malloc(sizeof(buffer));
strcpy(plates[idx++], buffer);
}
for (int i = 0; i < 8; i++)
{
printf("%s\n", plates[i]);
free(plates[i];
}
}
The pasted code just writes one and the same string over and over again, and I cant for the life of me figure out what Im doing wrong. When I debug the "while" method, I see that the buffer updates keep overwriting every entry to the plates array.
#Vlad from Moscow gave you an explanation for this:
that will not be alive after exiting the loop. And all elements of the array plates are set by the address of the first element of the array buffer2. That is within the for loop they all point to the same extent of memory.
"Im trying to print out the strings from a txt file in order."
As noted in comments fread() as used in your implementation is not the best way to read lines in a text file.
Answering these 2 questions (at minimum the first one) will provide important values to help in declaring and initializing the right sized (and shaped) buffers for reading lines from a file...
What is the longest line in the file?
How many lines are in the file? (may be optional if not storing all lines)
The following example(s) can be accomplished knowing only the answer to the first question, but knowing the answer to the second would be useful if it was necessary for example to store all of the lines into an array of strings. (This is out of scope here as you did not list that as a requirement for your code)
Unless you are comfortable with making an assumption on the maximum line length, i.e. hard-coded...
char line[guessed_max_line_length] = {0};
...a run-time assessment to determine the length of the longest line in the file is necessary to size the buffer such that it can safely contain lines that will later be read from file. Once this assessment is done, use the length of the longest line to create a line buffer during run-time. (dynamically allocate memory):
char *line = malloc(max_length + 1);
memset(line, 0, max_length + 1);
Using these methods, (and providing the implementation linked above) your code can be simplified to the following adaptation....
//prototype to get max line length in file
size_t longestLine(FILE *fi);
int main(int argc, char *argv[])
{
// Check for command line args
if (argc != 2)
{
printf("Usage: ./read infile\n");
return 1;
}
FILE *infile = fopen(argv[1], "r");
if(infile)
{
size_t max_length = longestLine(infile); //see linked implemenation from above
rewind(infile);//suggest adding this line to longestLine() implementation.
char *line = malloc(max_length + 1);
if(line)
{
memset(line, 0, max_length + 1);
while(fgets(line, max_length, infile))
{
fputs(line, stdout);
//or alternatively
//printf("%s", line);
}
free(line);
}
fclose(infile);
}
return 0;
}
I am writing a program that streams words from a text file and puts them into an array. I've also added a display of array data to see if everything is ok but I get a segmentation fault after compiling.
I am new to system programming so I am aware I might have done some basic mistakes. Please find the code below and tell me where have I gone wrong.
#include <stdio.h>
#define BUFFER 100
int main() {
char tab[BUFFER];
FILE *wp;
wp = fopen("tab_file_b_words.txt", "r");
if(wp == NULL)
{
printf("error/n");
return -1;
}
int i;
for(i=0; i<sizeof(wp); i++) {
if(wp != NULL)
fscanf(wp, "%s", &tab[i]);
else
break;
}
printf("Content: \n");
for(i = 0; i < BUFFER; i++) {
if(tab[i] != NULL)
printf("%s\n", tab[i]);
else
break;
}
fclose(wp);
return 0;
}
As of now you are having array of char
what you need is
char tab[BUFFER]; --> char tab[BUFFER][SOME_LENGTH];
And
fscanf(wp, "%s", &tab[i]); --> fscanf(wp, "%s", tab[i]);
%s expects null terminated char * but you are passing char.
printf("%s\n", tab[i]);
sizeof(wp) is size of pointer.
for(i=0; i<sizeof(wp); i++)
What you need is
while (1 == fscanf(wp, "%s", tab[i]))
{
...
}
This section:
for(i=0; i<sizeof(wp); i++) {
if(wp != NULL)
fscanf(wp, "%s", &tab[i]);
else
break;
}
Is problematic.
First, there are a couple of issues with the line: fscanf(wp, "%s", &tab[i]); It should be written as:
fscanf(wp, "%s", tab); //removed & and array notation.
Unlike int or float variable types, the name of your char array (i.e. tab) is already a pointer pointing to the address of the variable, making it unnecessary (and incorrect) to use the address of operator (&).
Related to above... (and likely cause of segmentation fault.)
Because the definition of tab is for a simple array of char ( char tab[BUFFER]; ), the notation tab[i] refers only to the ith byte (or char) of the array, not the entire array. Because of the "%s" format specifier used, the function fscanf() expects a char * not a char, making tab the correct argument to use.
If you want to use an array of lines the variable must be created as a 2D array of char:
#define NUM_LINES 100
#define LINE_LEN 80
int main() {
char tab[NUM_LINES][LINE_LEN] = {{0}}; // zero initialized array of
// NUM_LINE strings
// each of LINE_LEN-1 capacity
In the statement for(i=0; i<sizeof(wp); i++) {
sizeof(wp)
will be equal to the number of bytes of the pointer wp, either 32 or 64 depending on the target addressing of your application. This is probably not what you intended. (or want.)
Consider a different approach:
Given you are working with text files, try using a combination of while() and fgets() to read lines from the file. Then you can process each line based on its known syntax.
(Following example uses a single dimension char array for simplified illustration.)
char line[some_len];
wp = fopen(some_file_name, "r");
if(wp)
{
while(fgets(line, some_len, wp))
{
// use line. In this case, just print to stdout
printf("%s\n", line);
}
fclose(wp);
}
sizeof(wp) is the problem.
sizeof returns the length of a type in bytes and not the length of the file.
If you want to get the size of a file this may help you.
I have a program that reads file A and then copies the contents to file B.
I would like to write to file B every third character. I created a loop that rewrites every third item to a new char array. In file B I get strange characters. What am I doing wrong?
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
int main ()
{
int i;
char full_string[100];
char reduce_string[100];
char file_name_for_read[128];
char file_name_for_save[128];
printf("Enter file name for read...\n");
scanf ("%s", file_name_for_read);
strcat(file_name_for_read,".txt");
FILE *fileA;
fileA=fopen(file_name_for_read,"r");
printf("Enter file name for save...\n");
scanf ("%s", file_name_for_save);
strcat(file_name_for_save,".txt");
FILE *fileB;
fileB=fopen(file_name_for_save,"w");
while(fgets(full_string, sizeof(full_string), fileA) !=NULL)
{
for(i = 2; i < 100; i+=3)
{
reduce_string[i-=2] = full_string[i+=1];
}
fprintf(fileB, "%s", reduce_string);
}
fclose(fileA);
fclose(fileB);
}
What am I doing wrong?
Several things. At minimum,
In your inner loop, you iterate over the full length of full_string, regardless of how many of those bytes were actually read from the file by the most recent fgets().
In your inner loop, you invoke undefined behavior because the expression reduce_string[i-=2] = full_string[i+=1] has two side effects on the value of i that are unsequenced relative to each other.
In that expression, i - 2 is anyway not the index you want except when i is 2, because you increment i by 3 at each iteration. You'll end up filling some positions and skipping others.
You do not add a null terminator at the end of the data copied into reduce_string.
Your strategy does not anyway result in copying every third character of the file; rather, it copies every third character of each line. These differ unless all the line lengths of the input files are multiples of 3.
reads file A and then copies the contents to file B. I would like to write to file B every third character.
If lines are not important,
seems simple to read 3 characters and write the 3rd one.
for(;;) {
fgetc(fileA);
fgetc(fileA);
int ch = fgetc(fileA);
if (ch == EOF) break;
fputc(ch, fileB);
}
or
int ch;
do {
fgetc(fileA);
fgetc(fileA);
ch = fgetc(fileA);
} while (ch != EOF && fputc(ch, fileB) != EOF);
The easiest way is to use a different index for each array, that way each can go at their own speed.
int i,x;
for(i = 0, x=0; i < 1000; i+=3, x++)
{
reduce_string[x] = full_string[i];
}
fprintf(fileB, "%s", reduce_string);
Check this code out. In your code, you have reduce_string[i-=2] = full_string[i+=1]; — I don't know where you come up with it, but this was not working.
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
int main ()
{
int i;
char full_string[100];
char reduce_string[100];
char file_name_for_read[128];
char file_name_for_save[128];
printf("Enter file name for read...\n");
scanf ("%s", file_name_for_read);
strcat(file_name_for_read,".txt");
FILE *fileA;
fileA=fopen(file_name_for_read,"r");
printf("Enter file name for save...\n");
scanf ("%s", file_name_for_save);
strcat(file_name_for_save,".txt");
FILE *fileB;
fileB=fopen(file_name_for_save,"w");
while(fgets(full_string, 50, fileA) !=NULL)
{
int cnt = 0;
for(i = 2; i < strlen(full_string)-3; i+=3)
{
reduce_string[cnt++] = full_string[i];
}
fprintf(fileB, "%s", reduce_string);
}
fclose(fileA);
fclose(fileB);
}
I have a small sample program to illustrate my issue below: I have a simple text file with three words (each in a new line) which fscanf reads, assigns to a temporary variable and then transfers to a string array. Yet, the values do not seem to transfer to the array. Also, when I remove the comment // from the second printf in the while loop I get a seg fault.
I'm fairly new to C, so only now learning the usage of these functions! Thanks in advance for assistance!
#include <stdio.h>
#include <string.h>
int main (int argc, char* argv[])
{
char* words[15];
char tmp[45];
int i = 0;
FILE* fp = fopen("small", "r");
while (fscanf(fp, "%s", tmp) == 1)
{
printf("%s\n", tmp);
words[i] = tmp;
i++;
//printf("%s ", words[i]);
}
printf("\n");
printf("Words 0 = %s\n", words[0]);
printf("Words 2 = %s\n", words[1]);
printf("Words 3 = %s\n", words[2]);
fclose(fp);
}
Output
pears
apples
zipper
Words 0 = zipper
Words 2 = zipper
Words 3 = zipper
In your code, words[i] = tmp; is not the way to store each input to the words array. That only stores the base address of the tmp array into each words[i] and later, while printing, it actually prints the latest content of the tmp on every iteration.
If you want to get the contents of the tmp array into each words[i], you need to either
Allocate memory to each words[i] and use strcpy()
Use strdup() and assign that to words[i].
In either of cases, you have to free() the allocated memories before exit.
I had the same problem in the past.
The problem is that when you read from the file, the word is kept in the buffer, and then you store it to the variable temp.
The thing is that when you read the next word, the contents of the buffer change. And this affects the previous call too!
So you read "pears", you print "pears" and words[0] = "pears"
Then you read "apples", you print apples and words[1] = "apples". BUT ALSO words[0] = "apples" now!!
And so on...
What you need to do is before reading the file, to allocate memory with malloc for every words[i] and get it equal to "".
e.g. words[0] = "" etc.
Then when you start reading the file, you should use the strcpy() function for temp and words[i]. This will solve your problem.
I tried to answer this as simply as i could because in the past that issue troubled me and confused me a lot.
The first important problem with your code is this line
char* words[15];
It gives you an array of 15 char pointers (char*). That is not the same as an array of 15 strings. There are no memory for storing the strings.
To get memory for storing the strings, you can do:
char words[15][45];
// ^ ^^
// no * memory for each of the 15 strings
Now you have memory for 15 strings. Each string can be up to 44 chars.
With this change you don't need the tmpvariable - just read directly into words. Something like:
#include <stdio.h>
#include <string.h>
int main (int argc, char* argv[])
{
char words[15][45];
int i = 0;
FILE* fp = fopen("small", "r");
if (!fp)
{
printf("no such file\n");
return 0;
}
while ((i < 15) && (fscanf(fp, "%44s", words[i]) == 1))
{ // ^^^^^^^^ is the same as &words[i][0]
i++;
}
printf("\n");
int t;
for (t = 0; t < i; ++t)
{
printf("Words %d = %s\n", t, words[t]);
}
fclose(fp);
return 0;
}
Some other important changes added:
1) After fopen you must check for NULL
2) For scanf with %s always give a max size (i.e. %44s) so there can't be buffer overflow
3) Make sure to stop the while when you have read 15 strings (to prevent buffer overflow)
4) Only print as many strings as you have read in
Finally I added return 0 to the end of main
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.