C - Reading from a file and saving the info on a variable - c

im having a problem reading from these 2 files bellow, file1 and file2, and then saving their information in 2 variables.
From the file1 i want to save the name of channels, and from the file2 i want to save the name of the users and the channel where they are signed.
I was thinking of creating 2 typedef struct(shown bellow) and then create 2 variables(shown bellow) and open the files and put the info on those lists.
I also know of another way to do it which is making a 2D array like this char[100][100], the only problem with both these solutions is that I have to impose an upper limit on the amount of the channels the list/array has.
Im not sure if these are the best ways to do it or if there is a better and easier way to do it, could you guys help?
If you guys need any more information just say so, Thanks!
Edit1: i've added the read from the file1 code that i have right now and i think it is working or so it seems but my problem/question was more of is it the right way to save the information to a variable or is there a better/easier way to do it? thanks.
Channel channels[MAX_CHANNELS];
Registration registrations[MAX_REGISTRATIONS];
typedef struct{
char name_channel[20];
int id;
} Channel;
typedef struct{
char username[50];
char name_channel[20];
} Registration;
File1:
General
SO
PCD
FBD
File2:
2016-09-26 14:00:01 paul General
2016-09-26 14:01:11 mary SO
2016-09-27 10:33:17 paul SO
2016-09-27 13:32:10 rachel General
2016-09-27 13:32:12 rachel FBD
code to read the file(i have only done the file1 yet).
File *file1 = fopen("channels.txt", "r");
if(file1==NULL){ perror("Reading error: "); exit(1); } ;
char line[100];
int i = 0;
int w=0;
for(w;w<MAX_CHANNELS;w++){
channels[w].id=-1;
strcpy(channels[w].name, "n");
}
while(fgets(line, 100, file1) != NULL){
printf("Line read: %s", line);
line[ strlen(line) -1 ] = 0;
Channel a;
strcpy(a.name , line);
a.id=1;
channels[i]=a;
i++;
}
fclose(canais);
int k;
for(k=0; k<MAX_CHANNELS; k++){
if(channels[k].id!=-1)
printf("testing var with channels: %s\n", channels[k].name);
}

Just a few tips that might help(in the code comments) :) I think its fine the way you are doing it. I think this is extensible as well since you can add a new member to a struct if you want to enrich you data further. I have seen strtok used to parse through data quite a bit. Strtok should eliminate the need for you to overwrite the newline due to the way it works.
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#define MYSTRINGLEN (50) // In general "magic numbers"
//in code makes it hard to read, though these are fairly apparent,
//but try using #define where you can
typedef struct {
char name[MYSTRINGLEN];
// int id;
}Channel;
typedef struct {
char username[MYSTRINGLEN];
char name[MYSTRINGLEN];
} Registration;
int main(int argc, char *argv[]){
int i = 0;
//int w = 0; not needed
int k = 0;
char line[100];
Channel channels[BUFSIZ] = {{{0}}}; // num of brackets depends on num of nested data structure
Registration registrations[BUFSIZ] = {{{0}}};
/* init all to zero instead w/ bracket syntax
for (w = 0; w < BUFSIZ; w++){
channels[w].id = -1;
strcpy(channels[w].name, "n");
}
*/
FILE * file1 = fopen("channels.txt", "r");
//Many people use strtok to get done what you are doing here if you are interested
while(fgets(line,100,file1)){ // do not need to explicitly state NULL
printf("Line read %s\n", line);
line[strlen(line) -1] = 0;
//Channel a; You have already initialized a whole array of struct, just use them
strcpy(channels[i].name, line);
//a.id = 1;
//channels[i]=a;
i++;
}
fclose(file1);
for(k = 0; k < BUFSIZ; k++){
if (0 != channels[k].name[0]){ //can test if string was populated, dont need id flag
printf("testing var with channels: %s\n", channels[k].name);
}
}
return 0;
}
de here

Related

C File Reading storing user data from a text file to a structure array

I have a function getData() where it is supposed to read a text file "Users.txt" and store the data of the text file in an array of structures declared as user[20].
the struct is defined as:
typedef struct userTag {
int ID;
string10 password;
string20 name;
string30 address;
string15 contactNum;
} userType;
the text file format is as follows:
<ID> <password>
<name>
<address>
<contact num>
112 pass222
Ginge Akerwood
Camella Homes
0922294812
119 h3yo2
Marian Nilza Ginge
Camella
0999222444
this is my main program:
#include <stdio.h>
#include <stdlib.h>
#include "Data.h"
int main(int argc, char *argv[]) {
userType user[20];
getData(user);
display(user, 3);
return 0;
}
void display(userType u[], int nElem) {
int i;
for(i = 0; i < nElem; i++)
printf("User ID: %d\n", u[i].ID);
}
void getData(userType u[]) {
int i = 0;
FILE* fp_users;
char dump;
fp_users = fopen("Users.txt", "r");
while(fscanf(fp_users,"%d %s", &u[i].ID, u[i].password) == 2) {
fgets(u[i].name, 20, fp_users);
fgets(u[i].address, 30, fp_users);
fgets(u[i].contactNum, 15, fp_users);
fscanf(fp_users, "%c", &dump);
i++;
}
fclose(fp_users);
}
the output of the function display() is:
User ID: 112
User ID: 922294812
User ID: 999222444
I can't really find good resources on how to read files on the net so i had to ask here. also the format of the text file can't be changed so it has to be read that way.
After the scanf, the file pointer is on the newline at the end of the line. The first fgets returns the buffer with just that newline in it, and nothing else. The second fgets reads the line containing the name. Simplest fix is probably to use:
fscanf(fp_users,"%d %s\n")
but IMO this is hacky and fragile. It would be better to use either scanf or fgets exclusively, and don't mix the two. For example, instead of fgets, use fscanf(" %19[^\n]", u->name) to read the name. The leading space in the format string strips the whitespace for you. Note that I've assumed you are going to increment u so that -> is valid. It is a much cleaner syntax than u[i].name, and ought to be used.

Changing char[] in C

I looking for a answer and can't find nowhere. I hope you'll help me. I write a simple app which include struct with a name of worker and . But when i want to change value of name i can't do it. I don't know why. Maybe you can't help me or you know another ways to do it? My code:
struct workers {
char name[256]="no";
int pay=-1;
};
void addOne(struct workers work[20]) {
char name[256];
int i=0;
for (i = 0; work[i].name != "no"; i++) {}
printf_s("Enter name of worker: ");
scanf_s("%s", &name);
//-----error here-----
work[i].name = name;
}
int main()
{
int i;
struct workers work[20];
for (i = 0;i < 20; i++) {
if (work[i].name != "no") {
work[i].pay = 100 * i;
}
}
for (i = 0; i < 20; i++) {
printf_s("%s\t%d\n", work[i].name, work[i].pay);
}
return 0;
}
work[i].name = name;
The above line is where the problem is.
Change as below:
snprintf( work[i].name, sizeof(work[i].name), "%s", name);
What you have done is trying to change the base pointer of the array and not the name.
Also there were few more errors in the code, pls resolve them.
It is not possible to set default values to structure as you have done in C.
You have to write code to init each array instance name variable with "no" in a loop and then use one of the string comparison functions to compare the strings. And then call your addOne.

Unix - Writing a line from a file to a char* var, then saving it in integers

Question: I have a file, called ATM1, and it is filled with strings, for example(this is the format for everyline): O ilan 123 456 Which means - O stands for open account, ilan is username, 123 is password, and 456 is initial amount in my bank account.
After opening the file, iterating with a while loop while(((ret_in = read (in1, &buffer1, BUF_SIZE)) > 0)), I want to get the line's details and store them in the appropriate variables. for example the first char will be stored in a variable called letter or msg[0] whatever is more convenient for you, then there is a space and then username, then password, and optional stuff like balance, or maybe another account id (for transfer money purposes).
Every ATM machine should be a thread, it has its own file, for now it is just one file "ATM1" because I want it to work in the beginning for at least one file.
Current Problem:
Segmentation fault in the OpenFile function. I'm still not able to store the line's values in the appropriate variables and called the switch statement for opening account, etc.
Here is the current code:
#include <stdlib.h>
#include <stdio.h>
#include <pthread.h>
#include <fcntl.h>
#include <unistd.h>
#include <string.h>
#include <semaphore.h>
#define BUF_SIZE 8192
sem_t log;
void OpenNewAccount(int acc,int pw,int amount){
}
struct Account{
int number;
int password;
int balance;
};
//*Opens file for every ATM
void* openFile(void* args){
//To add later: while(true) { sleep(100); do next file's line }
//Open file
int* aargs = args;
int acc;
int pw;
int amount;
int target_acc;
int ret_in, in1,file;
char buffer1[BUF_SIZE];
int count = 0;
int i = 0;
char fn[5] = "ATM1";
char* msg;
file = open(fn,O_RDONLY|O_CREAT,0644);
while(((ret_in = read (file, &buffer1, BUF_SIZE)) > 0))
{
for(i; i<ret_in; i++)
{
if(buffer1[i]!='\n')
msg[i] = buffer1[i];
/* else{
if(count == 0){
count++;
break;
}
else
{
count = i + 1;
break;
}
}
*/
}
}
printf("%s", msg); //TEST: check msg
//Here we translate the message
/*
//Here we call the relevant function of the msg
switch (msg[count - 1]){
case 'O': OpenNewAccount(acc,pw,amount);
case 'D': Deposit(acc,pw,amount);
case 'W': Withdrawl(acc,pw,amount);
case 'B': Balance(acc,pw);
case 'Q': CloseAccount(acc,pw);
case 'T': Transfer(acc,pw,target_acc,amount);
}
*/
}
//*finish: Update log.txt and lock it
void WriteLog(char* msg){
int file;
char logName[8] = "log.txt";
sem_wait(&log);
file = open(logName,O_WRONLY|O_CREAT,0644);
strcat(msg,"\n");
write(file,&msg,strlen(msg));
close(file);
sem_post(&log);
}
int main(void)
{
int i,n,a;
sem_init(&log, 0, 1);
printf("Please enter the number of ATMs you want: \n");
scanf("%d", &n);
int bank; //bank with n ATMs
pthread_t thread[3];
printf("test\n"); //TEST: check msg
for(i = 0; i < 3; i++)
pthread_create ( &thread[i] , NULL , openFile , &i);
scanf("%d",&a);
}
Well, for one, you use i as an array index without ever initializing it. That could easily cause a SEGFAULT.
But honestly this whole thing is a mess. Your function names don't do what they say they do. You appear to be thrashing around almost randomly. I suggest you rethink your design from the beginning. Go through the "top down" design process you should have learned and figure out how to factor your code. Only then should you proceed.

Coredump in selfmade arrayList

i'm current working on a homework assesment where i'm programming a program ment to stitch textfiles with a piece of an ascii image to create a complete image of all the pieces. The way i intended to write the code is having a while loop looking through a directory finding the parts and adding them to an array. However in my AddFile method(or when i call it to be precise) i get a coredump.. I just started working with c so i dont know if it is very obvious to some of you why i get a coredump or more complicated. Also, i originaly wrote the addFile method to use and accept int's instead of the FILE type, at that point it worked perfectly without any coredumps so i suspect (but hey i might be wrong) that it went wrong when i tried to implement it with the FILE type.
#include <stdio.h>
#include <stdlib.h>
typedef struct{
int listSize;
int listCapacity;
FILE *fileStream;
}FileList;
void addFile(FileList* list, FILE file)
{
if((*list).listSize<(*list).listCapacity)
{
(*list).fileStream[(*list).listSize]=file;
(*list).listSize+=1;
}
else
{
FILE *tempArray = calloc((*list).listSize,sizeof(FILE));
for(int i=0; i<(*list).listSize; i++)
{
tempArray[i]=(*list).fileStream[i];
}
//Do something with array...
free((*list).fileStream);
(*list).listCapacity=((*list).listCapacity)*2;
(*list).fileStream=calloc((*list).listCapacity,sizeof(FILE));
for(int i=0; i<(*list).listSize; i++)
{
(*list).fileStream[i]=tempArray[i];
}
(*list).fileStream[(*list).listSize]=file;
(*list).listSize+=1;
free(tempArray);
}
}
int main()
{
FileList intList;
intList.listSize=0;
intList.listCapacity=1;
intList.fileStream=calloc(intList.listCapacity,sizeof(int));
int fileYcoord=0;
int fileXcoord=0;
while(1)
{
char fileName [100];
int fileNameLength=sprintf(fileName,"part_%02d-%02d",fileXcoord,fileYcoord);
FILE * pFile = fopen (fileName,"r");
if(pFile!=NULL)
{
printf("- ! found file: %s - name length : %d \n",fileName,fileNameLength);
addFile(&intList,*pFile);
fclose(pFile);
fileXcoord++;
}
else
{
if(fileXcoord!=0)
{
fileYcoord+=1;
fileXcoord=0;
}
else
{
break;
}
}
}
printf("size %d , %d",fileXcoord, fileYcoord);
free(intList.fileStream);
return 0;
}
The call to addFile() is dereferencing a FILE *, producing a value of type FILE. This is wrong, this is an opaque type and should always be handled by pointers.

C programming expression tree to postfix to solution using lines read from a file

I am terribly new at C programming.
I have stumbled upon a few answers. Some using the old syntax.
The problem is I have to create a program the will read a text file and use the read postfix lines to convert to an infix equation.
The text file would be something like this:
6 #this is the number ofcontainters
1 + 3 4 # it's no_operation_if op!=v then read value of nos mention
2 + 5 6
3 v 2.1
4 v 2.4
5 v 3.5
6 v 1.5
The C file will be read in the Ubuntu terminal where the text file is the only input and the output is the infix form.
A few suggestion as to how I will accomplish this using struct, arrays, and unions.
We were already given a format of creating struct opnode, vnode, and uniting them.
The array part I'm clueless how to transfer from reading to the array itself.
C is so weird compared to java as of this moment.
[EDIT]
Sorry I forgot to mention that this is homework... no longer postfix to infix. It's postfix to solve the equation.
Without prior knowledge of syntax and used to object oriented programming I don't know how to edit.
#include <stdio.h>
#include<stdlib.h>
#define MAXLENGTH 512
/* Codes by DocM
* struct opnode, vnode, union
*/
struct opnode{
char operator
int loperand;
int roperand;
};
struct vnode {
char letterv;
double value;
};
union {
struct opnode op;
struct vnode val;
} nodes[100];
/*node[2].op.loperand
*node[6].val.value
*/
/* This reads text file string input in terminal
* Then commands the text file be read
* etc.
* and everything else actually
*/
int main()
{
char text[MAXLENGTH];
fputs("enter some text: ", stdout);
fflush(stdout);
int i = 0;
int f = 0;
if ( fgets(text, sizeof text, stdin) != NULL )
{
FILE *fn;
fn = fopen(text, "r");
}
/* The code below should be the body of the program
* Where everything happens.
*/
fscanf (text, "%d", &i);
int node[i];
for(int j = 0; j<i;j++)
{
int count = 0;
char opt[MAXLENGTH];
fscanf(text,"%d %c", &count, &opt);
if(opt == -,+,*,)
{
fscanf(text,"%d %d", &node[j].op.loperand,&node[j].op.roperand);
node[j].op,operator = opt;
}
else
{
fscanf(text, "%lf", &node[j].val.value);
}
fscanf(text,"%lf",&f);
}
evaluate(1);
return 0;
}
/* Code (c) ADizon below
*
*/
double evaluate(int i)
{
if(nodes[i].op.operator == '+' | '*' | '/' | '-')
{
if (nodes[i].op.operator == '+')
return evaluate(nodes, nodes[i].op.loperator) + evaluate(nodes[i].op.roperator);
if (nodes[i].op.operator == '*')
return evaluate(nodes, nodes[i].op.loperator) * evaluate(nodes[i].op.roperator);
if (nodes[i].op.operator == '/')
return evaluate(nodes, nodes[i].op.loperator) / evaluate(nodes[i].op.roperator);
if (nodes[i].op.operator == '-')
return evaluate(nodes, nodes[i].op.loperator) - evaluate(nodes[i].op.roperator);
}
else
{
printf nodes[i].val.value;
return nodes[i].val.value;
}
}
I guess the basic algorithm should be:
Read the count for number of lines (not sure why this is necessary, would be easier to just keep reading for as long as there is indata provided, but whatever)
For each expected line:
Parse out the expected four sub-strings
Ignore the first, which seems to be a pointless linenumber
Print out the substrings in a shuffled order to create the "infix" look
Be done
I don't understand the part about the "v" operator, maybe you should clarify that part.
This seems a bit too much like homework for us to just blindly post code ... You need to show your own attempt first, at least.

Resources