Adding lines in a file to an array in C - c

I am trying to read a file, with a name on each line, like
Jim
Abby
Timothy
and store each name in a spot in an array so that I can later work with each individual name. This is the code that I have, but I do not think the names are stored right, because if I change the order of the names in the file, the actions on the name changes too. The actions depend on the name, not the placement.
FILE *ptr_file; // pointer to file
char name[100];
size_t k=0;
ssize_t read;
char *line = NULL;
while ((read= getline(&line, &k, ptr_file))!=-1)
{
fscanf(ptr_file, "%s", &name);
printf("%s ",name);
}
`I am trying to do something like this with the names
for (i =0; i <length-1; i++)
//for the length of the string add each letter's value up
{
num = num + name [i];
}
but when I switch the name's place in the list, the value of num changes as well.

Maybe something like this. In this code I'm assuming there will be less than 200 names in file. You can change this by change size of "names" array
FILE *ptr_file; // pointer to file
char names[200][100];
size_t k=100;
size_t namesCount = 0;
size_t read;
while ((read= getline(names[namesCount], &k, ptr_file))!=-1) //reading name to names array
{
printf("%s ",names[namesCount++]);//printf just readed name
}

getline() does the memory allocation for you when you pass a NULL pointer.
i have commented the code for explanation.
#include <stdio.h>
#include <stdlib.h>
#define THRESHOLD (5)
int main(int argc,char** argv) {
// the file containing the names (one in each line)
char* fn = "test";
// lets open the file (you should check the result!)
FILE* file = fopen(fn,"r");
// allocate memory for the array
char** names = (char**)malloc(THRESHOLD * sizeof(char*));
size_t i;
// set all the values to NULL
for(i=0; i<THRESHOLD; i++) {
names[i] = NULL;
}
// initialize the count
size_t count = 0;
// read all names until EOF and resize the array if needed
while(getline(&names[count],&i,file) != EOF) {
count++;
if(count >= THRESHOLD) {
names = (char**)realloc(names,(count+THRESHOLD)*sizeof(char*));
}
}
// resize (shrink) the array to the actual size
names = (char**)realloc(names,count * sizeof(char*));
// do something with the names (i just print them)
for(i=0; i<count; i++) {
printf("element %d, value %s",i,names[i]);
}
// you have to free the memory (allocated by getline)
for(i=0; i<count; i++) {
free(names[i]);
}
// you have to free memory (allocated by you)
free(names);
return 0;
}

It's difficult to see what you mean, but it looks like there are two fundamental logical problem you have (ignoring the specific technical points highlighted in the other answers).
1) The code reads one line using getline and discarding the result in line, then immediately reading more text from the file using fscanf.
2) Each name read from the file by the fscanf overwrites the name buffer, which is a single string of up to 99 characters plus a NULL terminator.
When you come to process the buffer it will contain only the last name read by a call to fscanf, or nonsense if there are zero or one lines in the file. Also, the fscanf format parameter "%s" tells fscanf to read a string up to the first whitespace (including tab or newline) character, which is probably fine for simple names, but not if you want first and second names.
This means that changing the order of the file will probably change which name is in the name buffer at the end of the routine that reads the file. This is why the value of num is different.

Related

C / Getting line string from text file and storing them in array/pointer

I want to get all lines from the text file and store them in my char** pointer (array of strings). The problem is that when I try to set indices for pointer's strings, the program assigns the last scanned sentence for all indices.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define MAX_LINE 10000
int main()
{
FILE *fp = NULL;
char line[MAX_LINE];
char** lines = (char**) malloc(10000*200*sizeof(char));
int count = 0;
fp = fopen("test.txt","r");
while(fgets(line,10000,fp)) {
lines[count] = line;
count++;
}
fclose(fp);
for(int i =0; i<2000;i++){
printf("%s",lines[i]);
}
return 0;
}
lets assume test.txt is like this:
Alice was beginning to get very tired of sitting by her sister on the
bank, and of having nothing to do: once or twice she had peeped into the
book her sister was reading, but it had no pictures or conversations in
it, and what is the use of a book, thought Alice without pictures or
conversations?
When I print like this, every time I get the last sentence (in this case conversations? ) in my text file. However, I want to set every scanned sentence from the text file to the different index in my char**. For example, I want to set like this:
lines[0] gives "Alice was beginning to get very tired of sitting by her sister on the"
lines[1] gives "bank, and of having nothing to do: once or twice she had peeped into the"
and so on.
You can't copy characters from one string buffer to another simply by assigning a pointer (all that does is to make the destination point to the source, as you have noticed).
Instead, you must actually copy the characters, using the strcpy function. So, instead of:
lines[count] = line; // Just makes each pointer point to the same buffer
use:
strcpy(lines[count], line); // Copies the CURRENT contents of "line"
You also have a severe problem in the way you are using your char** lines buffer. If you want an array of 200 lines, each with a maximum length of 10000 characters, you should allocate them as follows:
char** lines = malloc(200 * sizeof(char*)); // Make 200 pointers
// Now allocate 10000 chars to each of these pointers:
for (int i = 0; i < 200; ++i) lines[i] = malloc(10000 * sizeof(char));
Note: The 200 buffers will be uninitialized (contain random data) so, in your print loop, you should only use those you have copied real data to, using the count variable as the loop limit:
for(int i = 0; i < count; i++) {
printf("%s", lines[i]);
}
Also, don't forget to free the memory allocated when you're done:
for (int i = 0; i < 200; ++i) free(lines[i]); // Free each line buffer...
free(lines); // ... then free the array of pointers itself
strdup resolve the issue, free resources as said by Adrian when finished.
int main()
{
FILE *fp = NULL;
char line[MAX_LINE];
char** lines = (char**) malloc(10000*200*sizeof(char));
int count = 0;
fp = fopen("test.txt","r");
while(fgets(line,10000,fp)) {
lines[count] = strdup(line);
count++;
}
fclose(fp);
for(int i =0; i<count;i++){
printf("%s",lines[i]);
}
for (int i = 0; i < count; ++i) free(lines[i]);
free(lines);
return 0;
}
If you are looking for better performance look at my repo (https://github.com/PatrizioColomba/strvect)

C/ String data from file to array. Segmentation Fault

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.

fscanf in C with a text file with no spaces

I have a text file with names that looks as follows:
"MARY","PATRICIA","LINDA","BARBARA","ELIZABETH","JENNIFER","MARIA","SUSAN","MARGARET",
I have used the following code to attempt to put the names into an array:
char * names[9];
int i = 0;
FILE * fp = fopen("names.txt", "r");
for (i=0; i < 9; i++) {
fscanf(fp, "\"%s\",", names[i]);
}
The program comes up with a segmentation fault when I try to run it. I have debugged carefully, and I notice that the fault comes when I try and read in the second name.
Does anybody know why my code isn't working, and also why the segmentation fault is happening?
You have undefined behavior in your code, because you don't allocate memory for the pointers you write to in the fscanf call.
You have an array of nine uninitialized pointers, and as they are part of a local variable they have an indeterminate value, i.e. they will point to seemingly random locations. Writing to random locations in memory (which is what will happen when you call fscanf) will do bad things.
The simplest way to solve the problem is to use an array of arrays, like e.g.
char names[9][20];
This will gives you an array of nine arrays, each sub-array being 20 characters (which allows you to have names up to 19 characters long).
To not write out of bounds, you should also modify your call so that you don't read to many characters:
fscanf(fp, "\"%19s\",", names[i]);
There is however another problem with your use of the fscanf function, and that is that the format to read a string, "%s", reads until it finds a whitespace in the input (or until the limit is reached, if a field width is provided).
In short: You can't use fscanf to read your input.
Instead I suggest you read the whole line into memory at once, using fgets, and then split the string on the comma using e.g. strtok.
One way of handling arbitrarily long lines as input from a file (pseudoish-code):
#define SIZE 256
size_t current_size = SIZE;
char *buffer = malloc(current_size);
buffer[0] = '\0'; // Terminator at first character, makes the string empty
for (;;)
{
// Read into temporary buffer
char temp[SIZE];
fgets(temp, sizeof(temp), file_pointer);
// Append to actual buffer
strcat(buffer, temp);
// If last character is a newline (which `fgets` always append
// if it reaches the end of the line) then the whole line have
// been read and we are done
if (last_character_is_newline(buffer))
break;
// Still more data to read from the line
// Allocate a larger buffer
current_size += SIZE;
buffer = realloc(buffer, current_size);
// Continues the loop to try and read the next part of the line
}
// After the loop the pointer `buffer` points to memory containing the whole line
[Note: The above code snippet doesn't contain any error handling.]
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int main(void) {
char *names[9], buff[32];
int i = 0;
FILE *fp = fopen("names.txt", "r");
for(i = 0; i < 9; i++) {
if(1==fscanf(fp, "\"%31[^\"]\",", buff)){//"\"%s\"," does not work like that what you want
size_t len = strlen(buff) + 1;
names[i] = malloc(len);//Space is required to load the strings of each
memcpy(names[i], buff, len);
}
}
fclose(fp);
//check print & deallocate
for(i = 0; i< 9; ++i){
puts(names[i]);
free(names[i]);
}
return 0;
}
try this...
for (i=0; i < 9; i++)
{
names[i]=malloc(15);// you should take care about size
fscanf(fp, "\"%s\",", names[i]);
}

Possible memory corruption in 2-D array that stores the contents of a file

I've been able to work most of the problems out, but I've encountered a few that I'm uncertain as to how to address.
Let me explain: I have an example file that contains all the non-distinct combinations of the lower case alphabet up to length two (i.e. aa, ab, ac, ad...). The total number of non-distinct combinations is therefore 26^2, 676.
Knowing this is quite useful because I know that there are 676 lines, each containing a string of length 2.
Here is the code:
#include <stdlib.h>
#include <string.h>
int main(){
FILE* file;
//These would be passed as function arguments
int lines = 676;
int sLength = 2;
int C = lines+1;
int R = sLength+2;
int i,j; //Dummy indices
int len;
//Create 2-D array on the heap
char** mystring = (char**) malloc(C*sizeof(char*));
for(i = 0; i<C; i++) mystring[i] = (char *) malloc(R*sizeof(char)); //Need to free each element individually later on
//Create temporary char array
char line[R];
//Open file to read and store values
file = fopen("alphaLow2.txt", "r");
if(file == NULL) perror("Error opening file");
else{
i = 0;
while(fgets(line, sizeof(line), file) != NULL){
//Remove next line
len = strlen(line);
if((line[len-1]) == '\n') (line[len-1]) = '\0';
len--; //Decrement length by one because of replacing EOL with null terminator
//Copy character set
strcpy(mystring[i], line); //NOT certain if this works being that mystring is 2-D
i++;
}
mystring[C] = '\0'; //Append null terminator
}
for(i = 0; mystring[i]; i++){
for(j = 0; mystring[i][j]; j++){
printf("%c", mystring[i][j]);
}
}
getchar();
return 0;
}
To explain further, int C = lines+1 in order to append a null terminator. int R = sLength+2 in order to account for the \n present in the file, and the fact that fgets() always adds a null terminator. Therefore, in this example, the array should be of dimensions mystring[C][R] --> mystring[677][4]. The while loop replaces the \n with \0. The printout is correct, but at the very end of the printout, there is an odd string:
The characters after zz should not be there. This leaves me to wonder whether there is some memory corruption occurring somewhere in my program. Perhaps my arrays aren't large enough? I'm not sure. Otherwise, everything else appears to be functioning correctly.
Also, I will free the memory in the final program. Right now, I'm trying to get this to work properly. I'm also aware there are much easier ways to do this. For instance, std::string array would make this much easier. However, I'm am copying this array to a cuda enabled device, and cuda does not recognize that form.
Any constructive input is appreciated.
mystring is a char** so this call mystring[C] = '\0' is not quite correct. mystring[C] is a char* so you should not assign a char value to it. In this case the code works because \0 is 0 and NULL is also 0. What you can do is to replace this call with mystring[C-1] = NULL.
Also you assign NULL to the last row of mystring but it is not guaranteed that the file always has C - 1 lines(so that if you assign NULL to mystring[C-1] you are certain all the previous lines have been read). Better add a counter in the cycle reading lines and assign NULL to the next row in mystring.
As noted in a comment above mystring[C] is out of bounds for mystring so you should replace the index C with C - 1.
You don't have a terminating NULL entry in your mystring array, so your
for(i = 0; mystring[i]; i++)
will end up reading a bit too far. That may be the cause of your troubles.

Using fgets() to read multiple lines. How to go to the Next line?

So I am opening a file that contains cards data for a card game I am designing for my assignment, basically each line contains 104 characters and each line is equal to a deck of card.
I'm using a char **** because of
number of decks
num of players (4)
num of cards (13)
card is represented like 9H, 3D means nine of hearts and three of diamonds, so it uses 2 characters.
I want to use fgets() to read multiple lines but I'm not sure if this works...
for loop is just the way how the deckfile is set, I just want to know if the fgets will go to the next line when it hits \n...
di->cards = (char ****)malloc(sizeof(char***) * di->numDecks);
for (i = 0; i < di->numDecks; i++) {
di->cards[i] = (char ***)malloc(sizeof(char**) * 4);
for (j = 0; j < 4, j++) {
di->cards[i][j] = (char **)malloc(sizeof(char*) * 13);
for (k = 0, k < 13, k++) {
di->cards[i][j][k] = (char *)malloc(sizeof(char) * 3);
}
}
}
for (i = 0; i < di->numDecks, i++) {
for (j = 0; j < 13, j++) {
for (k = 0; k < 4; k++) {
while ((fgets(cards[i][k][j], 3, di->deckFile)) != NULL);
}
}
}
fgets() is often called in a loop, such as this:
FILE *fp;
char buf[260];// or char *buf, then use malloc - make index size appropriate length for anticipated line len.
fp = fopen("C:\\somedir\\card.txt", "r");
while(fgets(buf, sizeof(buf), fp)) //where sizeof(buf) is the length of
//line you anticipate reading in.
{
//do something with buf here;
//The input of fgets will be NULL as soon
//as its input fp has been fully read, then exit the loop
}
fclose(fp);
Your statement while((fgets(cards[i][k][j], 3, di->deckFile)) != NULL);
has a couple of issues, one is the ; at the end. It will just loop on this one line, and not give you a chance to do anything with the line that is read before it reads the next one. Also, 3 is probably not the length of line you want to read, is it? 3 is the buffer size that will hold your card data, but the line you read from the file will be longer.
So, in addition to these points, consider the other ideas in the comments, and make changes as indicated.
[EDIT] modified to read a file with "AS3D4C...(52 cards)" 4 lines
It will fill in enough spaces for 4 decks of cards. You can use this to
see how to read in the data. strtok (used before) works only when there
are delimiters, which if you can, I would recommend using instead of
long strings. Hope this helps.
(Note, I used no [mc]alloc()'s in this example.
#include <ansi_c.h>
#define FILENAME "C:\\dev\\play\\cards.txt"
int main()
{
int i, j;
FILE *fp;
char buf[260];// or char *buf, then use malloc - make index size appropriate length for anticipated line len.
char *cardTok;
char cards[208][3]; //4 players, 4 decks, each card is 3 bytes (eg. [A|S|\0], they all need a null termination)
memset(cards, 0, 208*3);
fp = fopen(FILENAME, "r");
j = 0;
while(fgets(buf, sizeof(buf), fp)) //where buf len is initialized at 260
//and well over the anticipated 104/line, including \n etc.
{ //note, fgets() will read up to n-1 characters and place a \0 at the end
//but will stop reading sooner if it sees end of line.
for(i=0;i<52;i++) //i is card number
{
cards[i+j][0] = buf[2*i+0];
cards[i+j][1] = buf[2*i+1];
cards[i+j][2] = 0;
}
j+=52;
}
fclose(fp);
}
My text file looked like this:
9H3D4SQhKD1H9H3D4SQhKD1H9H3D4SQhKD1H9H3D4SQhKD1H9H3D4SQhKD1H9H3D4SQhKD3D4SQhKD1H9H3D4SQhKDKD1H9H3D4SQhKD
6C9H3D4SQhKD1H9H3D4SQhKD1H9H3D4SQhKD1H9H3D4SQhKD1H9H3D4SQhKD1H9H3D4SQhKD3D4SQhKD1H9H3D4SQhKDKD1H9H3D4SQh
2D9H3D4SQhKD1H9H3D4SQhKD1H9H3D4SQhKD1H9H3D4SQhKD1H9H3D4SQhKD1H9H3D4SQhKD3D4SQhKD1H9H3D4SQhKDKD1H9H3D4SQh
3S9H3D4SQhKD1H9H3D4SQhKD1H9H3D4SQhKD1H9H3D4SQhKD1H1H9H3D4SQhKD1H9H3D4SQhKD3D4SQhKD1H9H3D4SQhKDKD1H9H3D4S
#include <stdio.h>
char *fgets(char *s, int size, FILE *stream);
fgets() reads in at most one less than size characters from stream and stores them into the buffer pointed to by s. Reading stops after an EOF or a newline.
be careful with this : If a newline is read, it is stored into the buffer. A terminating null byte ('\0') is stored after the last character in the buffer.
When you want to compare line , before you need to remove \n before null byte.
If you want to read single line.
char line[100]; // here you can use char *line=malloc(100);
fgets(line,sizeof line,file_stream);
printf("%s\n",line);
if you want to read multiple lines
char lines[20][100]; // here you can use char **lines=malloc(100);
i=0;
//if you use **lines allocate size for all lines with the loop or else you can allocate size inside loop and then read.
while((fgets(lines[i],SIZE_ALLOCATED_FOR_LINE,file_stream)!=NULL) && (i<20))
{
printf("%s\n",line[i++]);
}
The documentation says,
char *fgets( char *str, int count, FILE *stream );
char *fgets( char *restrict str, int count, FILE *restrict stream );
Reads at most count - 1 characters from the given file stream and
stores them in str. The produced character string is always
NULL-terminated. Parsing stops if end-of-file occurs or a newline
character is found, in which case str will contain that newline
character.
Also,
The return value is NULL on failure.
If the failure has been caused by EOF condition, additionally sets the eof indicator (see feof()) on stdin. If the failure has been caused by some other error, sets the error indicator (see ferror()) on stdin.
Also check for feof to ensure NULL was obtained due to EOF
If you want to take the fgets input and input all of it into an array of arrays or string array how could you do that. I have tried different things but get seg faults

Resources