Array of strings reading its input from file.txt C programming - c

I am having a problem and cant tell what is it.
struct arrayDB {
char *user[MAX_SIZE];
char *pass[MAX_SIZE];
char db[10][2];
};
void readFile(char fileName[100])
{
char* word ;
char line[90];
FILE *passFile;
int rowC=0;
int chk=0;
passFile=fopen(fileName,"rt");
while(fgets(line,90,passFile)!=NULL)
{
word=strtok(line," ");
rowC=rowC+1;
while(word!=NULL)
{
printf("Count=%i \n",rowC);
if(chk==0)
{
printf("word:%s\n",word);
DB.user[rowC]=word;
chk=1;
}
else
{
printf("word:%s\n",word);
DB.pass[rowC]=word;
}
printf("r=%s , c=%s\n",DB.user[rowC],DB.pass[rowC]);
word=strtok(NULL," ");
}
chk=0;
}
int i;
for(i=1; i<6;i++)
{
printf("- %s , %s \n",DB.user[i],DB.pass[i]);
}
}
but the output I am getting that all the array elements is the same value which is the last word in the file
as you can see in the pic
thanks

You're reading every line into the same string line. Then when you use strtok(), it's returning pointers into this string, and you're storing these pointers into DB. So all the records in DB are pointing to locations in line, which gets overwritten each time you read another line from the file. When everything is done, line contains the contents of the last line of the file, and all the DB entries point to that.
Another problem is that line is a local variable, and pointers to it become invalid when the function returns.
To solve both problems, you need to make copies of the string and store these in DB. For example:
DB.user[rowC]= strdup(word);
This also means that when you're done with a DB record, you need to call free(DB.user[i])

Some suggestions:
First, learn to use a debugger. There are free ones, get one and turn it on to find all of these errors (that is what I did here)
Next, for the code example you show to compile, the struct definition needs to support your code (currently, DB is not defined)
typedef struct
{
char *user[MAX_SIZE];
char *pass[MAX_SIZE];
char db[10][2];
}arrayDB;
arrayDB DB;//define DB
Next,
you need to allocate space for your string arrays:
something like:
for(i=0;i<MAX_SIZE;i++ )
{
DB.user[i] = malloc(100);
DB.pass[i] = malloc(100);
}
Next, don't forget to free them when done using them.
for(i=0;i<MAX_SIZE;i++ )
{
free(DB.user[i]);
free(DB.pass[i]);
}
Next, you cannot assign a string using an equal operator:
DB.pass[rowC]=word;
use strcpy (or some other string function) instead:
strcpy(DB.pass[rowC],word);
Next, this line:
printf("r=%s , c=%s\n",DB.user[rowC],DB.pass[rowC]);
Is called after a conditional statement where either DB.user[rowC] or DB.pass[rowC] will be written to, never both. Suggest splitting this printf statement to print one or the other, and place it into the appropriate conditional branch.

Related

Dynamic fscanf into an array

I am trying to place some text into a structure part of my array is a array which takes part of the text.
For example my structure is:
struct animal
{
char animal_Type[11];
int age;
int numberOfLegs;
int walksPerDay;
char favoriteFood[];
};
I will then have input such as:
dog,2,4,2,biscuits,wet
cat,5,4,0,biscuits,wet,dry,whiskers
bird,1,2,0,birdseed,biscuits,bread,oats,worms,insects,crackers
I have a working solution that places all the values up to walks per day into the structure, however I want to be able to place the food items into Favorite food. I have a dynamic array for this, but i'm not sure how to read remaining text into the favoriteFood array.
The code used is:
fp = open("animals.txt","r");
struct animal *animal = malloc(sizeof(sturct animal)*3);
int i = 0;
if(fp != NULL) {
while(i < 3) {
fscanf(fp,"%s %d %d %d %s",
animal[i].animal_Type,
animal[i].age,
animal[i].numberOfLegs,
animal[i].walksPerDay,
animal[i].favoriteFood); // need to be able to enter the string of food into here
i++
}
How would I go about doing this?
First of, your struct doesn't match what you've said in the comments.
char favoriteFood[];
The above is an array of char, so couldn't possibly hold a list of favourite foods except if it were one string. And since the size of the array is unspecified, you'd not be able to fill it like you have been either. Instead what you actually want is
char **favoriteFood;
unsigned int favoriteFoodSize;
That will let you create an expanding list of strings to fit whatever data you need to accommodate.
As for reading it in, the best way would be to read the entire line in using fgets and then use something like strtok to break the line up by your separator character. First define a very large string to hold the entire line and a char * to hold each field.
char buffer[1024];
char *token;
And then to the main loop would be something like this:
while(fgets(buffer,1024,fp)) {
token=strtok(buffer,",");
strcpy(beasts[i].animal_Type,token);
token=strtok(NULL,",");
beasts[i].age = atoi(token);
/* etc... */
}
You'd need to check whether token is ever NULL to cope with the possibility of short lines and handle it accordingly. And also make sure that the string copied into animal_Type isn't longer than 10 characters...or alternative make it a char * so you can have any size of string.
For the favoriteFood, you'll need to use realloc to increase the size of it to accommodate each new food added and keep going through the string until you run out of tokens.
token=strtok(NULL,",");
if(token) {
beasts[i].favoriteFood=malloc(sizeof(char *));
beasts[i].favoriteFood[0]=strdup(token); // Need to index using 0 as favoriteFoodSize won't have a value yet
beasts[i].favoriteFoodSize=1;
token=strtok(NULL,",");
while(token) {
beasts[i].favoriteFood=realloc(beasts[i].favoriteFood,(beasts[i].favoriteFoodSize+1)*sizeof(char *));
beasts[i].favoriteFood[beasts[i].favoriteFoodSize]=strdup(token);
beasts[i].favoriteFoodSize++;
token=strtok(NULL,",");
}
}
The last food will have a \n in it as fgets keeps it in the buffer it reads, so you could use that to tell if you've finished processing all the foods (you will also need to remove it from the last food). Or if you don't have it, you know the line was longer and you'll need to read more in. But that seems unlikely based on your sample data.
And since you're doing lots of memory allocation, you should ensure that you check the values returned to make sure you've not run out of memory.

C File input & output

I made a simple dictionary code, and surfed for an hour, and I found a file I/O code. But my compiler(I use Microsoft visual C++) says my code(unfortunately, the core part of the code) is wrong. but I can't get it. What is actually wrong and why???
/*
DosDic ver 1.0.0 2015-07-03
*/
#include<stdio.h>
#include<string.h>
char key = 0;
FILE *fp; //set a file pointer var
fp = fopen("dicdata.dat","r"); //open a file
int b = 0;
int trial = 0;
char result[];
char searchfor[] = fp; //save a whole list of dictionary in a var
int i;
char sb[]; //var for search in a list
int getsearchtrial(char sb[]){
for(i=0;i=strlen(sb);i++){ //how much I tried to reach to the word
switch((int)searchfor[b]-(int)sb[i]){ //are two alphabets same?
case 0 :
default : i=0;
}
b++; //keep finding in a list
trial++; //try again
}
return trial;
}
int adress;
int mainpage(){
printf("Type what you want to search : ");
scanf("%c",sb[ ]);
getsearchtrial(sb[ ]) - strlen(sb[ ]) = adress; //where the word is located in the list
for(i = adress;i = adress + 30; i++){ //print
printf("%c",searchfor[i]);
}
printf("Thank you for using DosDic ver.1.0!"); //thank you!
}
void main(){ //call all those functions
mainpage();
fclose(fp); //close list
}
//and whats wrong with this? i cant even get it, but it's not working
Multiple issues.
First of all, you can't assign the result of fopen to fp outside the body of a function; you must move fp = fopen("dicdata.dat", "r"); to within the body of one of your functions (getsearchtrial most likely).
Secondly, you don't read from a file by simply assigning a file pointer to an object; you must use a library function like fscanf or fread or fgets. Assuming your file contains a single string of length 80, you'd need to write something like
char searchfor[81] = {0}; // make sure string is initially empty,
// extra space for string terminator
if ( !fgets( searchfor, sizeof searchfor, fp) )
{
// error reading from file
}
Of course, this depends on how your input file is structured. If it contains a list of strings, then you'll need to use a multidimensional array (or some other structure).
Third, when you declare an array, must specify its size before you can use it. result and searchfor are incomplete array definitions.
Finally, this line
getsearchtrial(sb[ ]) - strlen(sb[ ]) = adress;
needs to be reversed; the target of an assignment must be on the left of the assignment operator.
You need to step back and learn how to write C code from the ground up.
There is so much wrong I'm not even going to itemise it all here - most of it seems to stem from your lack of understanding of arrays in C.
Most notably...
You can't declare an array and not initialise it or specify a size.
You can't assign a FILE * to a char array (and expect decent
results).
You can't execute a statement like fp = fopen at the
global scope like you are.
Try this tutorial and you may fix 95% of your problems, then go from there.

How can i copy certain parts of an array to another in C?

So what my program should do is: Read a .txt file with this piece of code.
FILE *fp;
char filename[40],part1[4],part2[4];
int c=0,pt1,pt2;
printf("\nEnter a file name to open: ");
gets(filename);
if ((fp = fopen(filename, "r"))!= NULL)
{
printf("\nThe file %s was opened successfully!",filename);
}
else
{
printf("\nThe file didnt open succesfully!");
}
And then store each line in the row string like this.
fgets(part1,4,fp);
pt1 = atoi(part1);
struct input
{
char name[20],row[30],code[3],nPieces[3],needed[3],usage[3],nUses[3];
};
struct input list[pt1];
while (c++ < pt1 )
{
fgets(list[c].row,30,fp);
printf ("\n%s", list[c].row);
}
But the problem is that after that i must take the row string and cut it into pieces (for exp the 1st line of txt was <1 Glass 2 0 9 3 1> where each number represents something) So what i want is to put the "1" into the code[3] string the "Glass" into the name[30] string etc. I tried to make it work using the isspace() scaning the row string and whenever it found a space it would copy the row array from 0-(the space - 1) using strncpy(). For some reason when ever i run tha program is stops working. Anyone that could suggest anything?
It seems you want to allocate an array of size pt1, but that won't work because this is compile time and the value of pt1 is not known.
With:
struct input
{
char name[20],row[30],code[3],nPieces[3],needed[3],usage[3],nUses[3];
};
you declare a variable, but it seems you want to define a type, so:
typedef struct input
{
char name[20],row[30],code[3],nPieces[3],needed[3],usage[3],nUses[3];
};
and then later you must malloc the memory:
struct input list= calloc(pt1, sizeof(struct input));
The statement
struct input list[pt1];
should give a compiler error (does with my compiler).
So what i want is to put the "1" into the code[3] string the "Glass"
into the name[30] string etc.
It's much easier with sscanf() rather than isspace() and strncpy():
sscanf(list[c].row, "%2s%19s%2s%2s%2s%2s",
list[c].code,
list[c].name, list[c].nPieces, list[c].needed, list[c].usage,
list[c].nUses)

two functions - getting char and work on pointer

in C:
Im trying to write 2 functions one is getting from the user a line (string) and sending it to another function that remove (if exist) blank space from start of the string.
I am trying to make the "remove_space" function work on pointer, alter it by making it point to the continue of the string without the space.
for example:
lets say the user type:
" hi123"
and i save this string in some pointer
i want to send this pointer to "remove_space" function and make the pointer point at "hi123" without the spacing starts...
for now.. i have some problems with the pointers from what i see.
this is what I wrote:
void remove_space(char** st1)/**function to remove space**/
{
char* temp_st = strtok(st1, " ");
strcpy(st1, temp_st);
}
void read_comp(void)
{
printf("read_comp FUNCTION\n");
char* st1; /**read the rest of the input**/
fgets(st1,30,stdin);
remove_space(st1);
printf("%s\n",st1);
}
You haven't allocate memory to store a string in st1.
char st1[30];
Also, you don't need a char** here.
void remove_space(char *st1)
{
char *temp_st = strtok(st1, " ");
strcpy(st1, temp_st);
}

C - Build dynamically allocated array of pointers to structures filled with input from file

I need to build an array of pointers to dynamically allocated structures (DBrecord) and fill that array with input from another file. Not sure how to approach this.
The data file will have the number of entries first, followed by entries in a specific order.
numOfEntries
lastName firstName studentID year gpa expGradYear
example:
1
Doe John 12345678 senior 3.14159 2015
Here's the code I have so far:
class.h
typedef enum {firstYear, sophomore, junior, senior, grad} class;
main.c
#include <stdio.h>
#include <stdlib.h>
#include "class.h"
int main(){
//DBrecord is name for structure
struct DBrecord{
int DBrecordID; //ID for each entry, range 0-319
char *last; //student last name
char *first; //student first name
char studentID[8]; //student ID
int age; //student age
class year; //year in school
float gpa; //GPA
int expGradYear; //expected graduation year
};
int numEntries; //total number of entries, first num in data file
struct DBrecord **ptrToDB;
//scan first int in data file and assign to numEntries
scanf("%d", &numEntries);
//allocate memory for structures, each is 36 bytes
*ptrToDB = malloc (sizeof(struct DBrecord) * numEntries);
//free allocated memory
free(ptrToDB);
//build an array of pointers to dynamically allocated structures
//fill that array with input from data file
//build 7 arrays of pointers to DBrecords, one for each field except DB ID
//sort each a different way
//note the 7 arrays are pointers, no copying
//print each of the 7 sorted arrays
return 0;
}
I can give you some snippets on how to look at this problem.
First - I would avoid using class name for any variable, because in many object-oriented programming languages (including C++) it is a keyword and can't be a name of variable.
Structure DBrecord
It might be a good idea to use typedef. Then you could declare a struct variable without using "struct DBrecord", just "DBrecord". But that's optional. This is how it would look:
typedef struct {
int DBrecordID; // ID for each entry
char *lastName;
char *firstName;
char studentID[8];
...
} DBrecord;
Loading from file
In this homework you have the number of records at the beginning of the file, so you don't need to take "extra" care about it. Just load it.
Let's assume the file is like this:
2
Doe John 12345678 senior 3.14159 2015
Carl Boss 32315484 junior 2.71 2013
Therefore the first thing you do with your file is to open it.
Portable way of working with files is by using FILE pointer. Let me show it (stdio.h must be included):
FILE *filePtr; // Define pointer to file
if((filePtr = fopen("records.txt", "r")) == NULL) // If couldn't open the file
{
printf("Error: Couldn't open records.txt file.\n"); // Printf error message
exit(1); // Exit the program
}
Then you can read from your file by line using fgets() to read by lines or fgetc() to read by characters. This is how you can read number of records (remember that it's on the first line and we've just opened the file - we are at the beginning of the file):
char buffer[100]; // Define the buffer
fgets(buffer, 100 /* size of buffer */, filePtr);
Now buffer contains the first line (without \n character) - number of records. Continue with converting the num's characters into integer (here stdlib.h also has to be included):
int numOfRecords = atoi(buffer);
Allocating enough DBrecords
Now you know the number of records, you can allocate enough space for them. We will use array of pointers.
DBrecord **recs;
recs = (DBrecord **) malloc(sizeof(DBrecord *) * numOfRecords);
Now we have created array of pointers, so now we need to allocate every individual pointer as a DBrecord. Using cycle:
int i;
for(i = 0; i < numOfRecords; i++)
{
recs[i] = (DBRecord *) malloc(sizeof(DBrecord));
}
Now you can acces array elements (= individual records) like this:
recs[0]->lastname /* two possibilities */
*(recs[0]).lastname
an so on.
Filling array with values from file
Now you know everything to get the homework done. This way you fill the array:
int i;
for(i = 0; i < numOfRecords; i++)
{
// Content of cycle reads one line of a file and parses the values into recs[i]->type...
/* I give you small advice - you can use fgetc(filePtr); to obtain character by character from the file. As a 'deliminer' character you use space, when you hit newline, then the for cycle continues.
You know the order of stored values in the file, so it shouldn't be hard for you.
If you don't get it, let me now in comments */
}
Is it somehow clearer now?
EDIT: File name as main's argument
There are usually two ways of 'passing' arguments (values) to a program. They are:
./program < records.txt // Here the file's name is passed to program on stdin
./program records.txt // Here the file's name is passed as value in `argv`.
If you can choose, I strongly recommend you the second one. Therefore you need to have main defined as this:
int main(int argc, char *argv[]) // this is important!
{
// code
return 0;
}
argc is integer which says, how much arguments were passed to the program. argv is array storing them. Remember, that the first argument is name of the program. Therefore if you need to check for it, do it:
if(argc != 2)
{
printf("Number of arguments is invalid\n");
exit(1); // exit program
}
Then you only put argv[1] into fopen function, instead of the string "records.txt".
EDIT 2: Reading file's name from stdin
Another approach must be done, if the name of the records file is passed to the program via ./program < records.txt, which means that "records.txt" (without quotes) will be passed (redirected) to program's standard input.
Therefore to handle that, you can do this:
char filename[50]; // buffer for file's name
scanf("%s", &filename); // reads standard input into 'filename' string until white character appears (new line, blank, tabulator).
Then you have your desired file's name in filename string.
Where to start, where to start.....
//allocate memory for structures, each is 36 bytes
mem = (double *)malloc(36*numEntries);
malloc should be malloc (sizeof (struct DBRecord) * numEntries);
don't cast the result of malloc
2a. you forgot stdlib.h
Why include class.h?
your array of pointers are not double, they are instead
struct DBRecord **ptrToDB;
*ptrToDB = malloc (sizeof (struct DBRecord) * numEntries);
This should get you started.
Next, free() should be the last thing you do before leaving your function (and yes, main is a function)
You'll have to insert some code for the next part, I can't do the homework for you.

Resources