I have file.txt with
123456 2,00 beer
234567 2,50 milk
345678 3,30 ice cream
I want to put this info in my dynamic two-dimensional array:
char **dataBase;
dataBase = (char**)malloc(NUM_OF_PROD * sizeof(char*));
for(i = 0; i < NUM_OF_PROD; i++){
dataBase[i] = (char*)malloc(MAX_BUFFER* sizeof(char));
}
But I don't know how. We have here 3 lines. If it was a C++, I would use getline() but in this situation I can't find a solution.
I usually use the fgets() function to a file on a line-per-line basis (provided it is a text file).
#include <stdio.h>
#include <stdlib.h>
#include <ctype.h>
#include <string.h>
#define LINELEN 200
#define NAMELEN 40
struct PRICELIST
{
char item[NAMELEN];
float price;
unsigned int order_no;
struct PRICELIST *next;
struct PRICELIST *prev;
};
void list_print_node (struct PRICELIST *node)
{
printf ("%d %4.2f %s\n", node->order_no, node->price, node->item);
}
void list_print (struct PRICELIST *head)
{
printf ("Order # Price Item\n");
printf ("------------------------------\n");
while (head)
{
list_print_node (head);
head = head->next;
}
}
void list_delete (struct PRICELIST *head)
{
if (head)
{
/* recursive call */
list_delete (head->next);
free (head);
}
}
struct PRICELIST *list_read (char *filename)
{
FILE *file;
char line[LINELEN];
struct PRICELIST *pricelist, *node, *prev;
char *p;
size_t len;
file = fopen (filename, "r");
if (file == NULL)
{
perror (filename);
return NULL;
}
pricelist = NULL;
prev = NULL;
while (1)
{
if (fgets (line, sizeof(line), file) == NULL)
break;
/* eat the newline at the end of the buffer, be CR/CRLF agnostic .. */
len = strlen (line) - 1;
if (line[len] == '\r' || line[len] == '\n')
{
line[len] = '\0';
len --;
}
if (line[len] == '\r' || line[len] == '\n')
line[len] = '\0';
/* allocate a new node in the list */
node = malloc (sizeof (struct PRICELIST));
if (node)
{
/* now use sscanf() for getting single elements */
sscanf (line, "%d %f", &node->order_no, &node->price);
/* since the item name might contain spaces this is not so easy .. */
p = line;
while (isspace(*p)) p++;
while (isdigit(*p)) p++;
while (isspace(*p)) p++;
while (isdigit(*p)) p++;
while (ispunct(*p)) p++;
while (isdigit(*p)) p++;
while (isspace(*p)) p++;
strncpy (node->item, p, sizeof(node->item));
node->next = NULL;
/* if this is the first node of the list assign the head to it */
if (pricelist == NULL)
pricelist = node;
/* append the new node to the end of the linked list */
if (prev)
prev->next = node;
node->prev = prev;
/* save it for the next entry */
prev = node;
}
}
/* we are done with the file, close it */
fclose (file);
return pricelist;
}
/* let's test it */
int main (int argc, char *argv[])
{
struct PRICELIST *pricelist;
if (argc < 2)
{
printf ("Usage: %s filename\n", argv[0]);
return 0;
}
pricelist = list_read (argv[1]);
if (pricelist)
{
/* print the list */
printf ("This is the price list (filename '%s'):\n\n", argv[1]);
list_print (pricelist);
/* delete the list */
list_delete (pricelist);
}
return 0;
}
In the comments you mentioned you were only concerned about actually reading a file.
Here's how you'd go about reading a file (currently untested, binary mode):
#include <stdio.h>
int main()
{
FILE *file = fopen("path/to/your/file/yourfile.txt", "rb");
if(!file) return 1; //something went wrong!
long size = fseek(file, 0, SEEK_END);
char *buf = malloc(size);
fread(&buf, size, 1, file); //read all contents, once
fclose(file);
free(buf); //because this is just an example
return 0;
}
For more info on reading a file, just do a quick google search and you'll find almost everything you're looking for.
You can implement your own version of getline using fgetc and realloc.
#include <stdio.h>
#include <stdlib.h>
char *getline(FILE *file)
{
size_t size = 16; // Size of memory allocated for line
size_t len = 0; // Characters read
char *line = malloc(size);
// Return NULL if memory allocation fails
if (line == NULL)
return NULL;
for(;;) {
int c;
switch (c = fgetc(file)) {
// If End Of File is met, return the line up until this point
// if anything has been read
case EOF:
if (len == 0) {
free(line);
return NULL;
}
else {
line[len+1] = '\0';
return line;
}
case '\n':
line[len+1] = '\0'; // NUL terminate the string
return line;
default:
line[len++] = c;
}
// If the string plus NUL terminator is longer than size
// double the size of line
if (len + 1 >= size) {
size *= 2;
line = realloc(line, size);
// Return NULL if memory allocation fails
if (line == NULL)
return NULL;
}
}
}
There are also many free/open source implementations of the same function that can be found online. For instance this GPL 2 one. If you are on a POSIX system (e.g. OS X or Linux) there is already a version of getline found in stdio.h.
Related
Im using fread() and fseek() togather to gather parts of a string. I'm not using fread() on the whole line though.
I'd take the whole line but to my knowledge you cannot use fseek() on a character array correct?
`int parse(const char *f, const struct stat *flightD, int type){
//file pointer
Airport_S *Air_Pts = (Airport_S *)malloc(sizeoftype(Airport_S));
FILE *fp;
//char need[10];
char airLineFile[2];
char chkAirPt[3];
fp = fopen(f, "r");
if(type == FTW_F){ // test for 'type' of FTW_F
//check to see if the file opened successfully
if(fp == NULL)
printf("Cannot open file %s", f)
return 1;
while (!(FEOF)){
//fgets(need,10,fp)
//must return zero to parent funtion to continue tree traversal
// ?? While current dir != originally called dir?
//open the file, read it's contents and assess them
fseek(fp, 5, SEEK_SET) //set FP to right before airport code
chkAirPt = fread(chkAirPt,sizeof(char),3, fp)
fseek(fp,0,SEEK_SET);
//combine the airline abbreviation with '.txt'
airLineFile = strcat(fread(airLineFile, sizeof(char), 2, fp),".txt");
//if the struct has no values in it, populate it with this first one.
if(Air_Pts->airport == NULL){
//Set info for very first node
Air_Pts->airPt=strcpy(Air_Pts->airport, chkAirPt);
fseek(fp,0,SEEK_SET);
Air_Pts->fltInfo->airLine=airLineFile;
Air_Pts->fltInfo->next = NULL;
Air_Pts->fltInfo->prev = NULL;
Air_Pts->next = NULL;
Air_Pts->prev = NULL;
//what is the file going to do after this?
}
else if(strcmp(Air_Pts->airport, chkAirPt) == 0){
if(strcmp(Air_Pts->fltInfo->airLine, airLineFile) == 0){
Air_Pts->fltInfo->occ++;
}
else
Air_Pts->fltInfo = addAirline(Air_Pts->fltInfo);
}
// some code
return 0;
else //anything other than a file -or- FTW_D
return 1;
}
}
}`
You are working too hard. Just read and discard the data you don't need. For example:
/* Sample input line: AA43 DTW2315 ... */
/* Read first two columns of each line of a text file into a struct */
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
struct data {
char airport[32];
char flight[32];
struct data *next;
};
FILE * Fopen(const char *path, const char *mode);
void * xmalloc(size_t);
void
push(struct data **head, struct data new)
{
struct data *t = xmalloc( sizeof *t);
t->next = *head;
strncpy(t->airport, new.airport, sizeof t->airport);
strncpy(t->flight, new.flight, sizeof t->flight);
*head = t;
}
int
main(int argc, char **argv)
{
FILE *ifp = argc > 1 ? Fopen(argv[1], "r") : stdin;
struct data *head = NULL;
struct data this;
int line = 1;
int c = 0;
while( (c = fscanf(ifp, "31%s %31s", this.airport, this.flight)) == 2) {
push(&head, this);
/* Discard until the end of line */
while( (c = fgetc(ifp)) != EOF ) {
if( c == '\n') {
line += 1;
break;
}
}
}
/* Print all the records in reverse order */
for( ; head; head = head->next ) {
printf(" %s: %s\n", head->airport, head->flight);
}
return 0;
}
FILE *
Fopen(const char *path, const char *mode)
{
FILE *rv = fopen(path, mode);
if( rv == NULL ) {
perror(path);
exit(EXIT_FAILURE);
}
return rv;
}
void *
xmalloc(size_t s)
{
void *rv = malloc(s);
if( rv == NULL ) {
perror("malloc");
exit(EXIT_FAILURE);
}
return rv;
}
How can i do above things in one single programme with multiple duplicates keys and csv. type input data file?
EDIT: assumed KEY "," DATA "\n" (no whitespace, for brevity) and appended a short sketch at the end such that the OP has a start.
I cannot repair it because I don't know the input but I can point out some of the errors you made. See comments in code
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define MAXNAMELENTH 64
#define MAXDATALENTH 1465
typedef struct node {
char name[MAXNAMELENTH];
char data[MAXDATALENTH];
struct node *left;
struct node *right;
} node;
node *root;
node *search(node ** tree, char *key, int count, FILE * fp_out);
node *insertion(node * r, char *key, char *value);
void deltree(node * tree);
char *strtok_r(char *str, const char *delim, char **nextp);
int main(int argc, char *argv[])
{
node *root;
node *tmp;
FILE *fp;
FILE *outputfile;
FILE *keyfile;
FILE *fp_key;
int i;
int counter = 0;
int bufsize = MAXDATALENTH + MAXNAMELENTH;
int keyfilelen = MAXNAMELENTH;
char *keyread;
char *buffer, *saveptr;
char *line = NULL;
char *keyin = NULL;
char *valuein = NULL;
char inputkey[MAXNAMELENTH];
char *target_key = NULL;
char *keyline = NULL;
root = NULL;
/* Inserting nodes into tree */
buffer = (char *) malloc(bufsize * sizeof(char));
if (buffer == NULL) {
// use the proper macros, please
exit(EXIT_FAILURE);
}
// Check outputs! Always check outputs!
// I just assume that it has not been done here for simplicity
// and fear of posting-size limits (limit is 30k IIRC, that's a lot of code)
fp = fopen(argv[1], "r");
outputfile = fopen("outputfile.txt", "a");
// this is an infinite loop. How do you break out?
while (1) {
// fgets() returns NULL in case of EOF and error
// (yes, both, so check, e.g.: with ferror())
fgets(line, bufsize, fp);
buffer = line;
// I'm not fully sure, but I think you wanted a "=" instead of a ","
// Please switch on warnings for your compiler
keyin, strtok_r(buffer, ",", &saveptr);
// NUL delimited? Really? Are you sure strtok_r() can handle it?
valuein = strtok_r(NULL, "\0", &saveptr);
// insertion() returns a node
insertion(root, keyin, valuein);
}
/* Search node into tree */
// Wrong type: keyfile is a filepointer (FILE *), not a string (char *)
if (scanf("%s", keyfile) != EOF) {
// hu? Please switch on warnings for your compiler
keyfile = fopen(argv[4], "r");
// where's keyfile? Gone?
while ((fgets(keyline, keyfilelen, fp_key))) {
keyread = strtok_r(keyline, "\n", &saveptr);
search((&root), keyread, counter, outputfile);
}
// Please use braces, even here, thank you
if (keyline) {
free(keyline);
}
fclose(keyfile);
}
// This reads keys given as arguments at programstart,
// that's not what the teacher wanted
for (i = 3; argv[i] != NULL; i++) {
target_key = argv[i];
search((&root), target_key, counter, outputfile);
}
// This program does not read from stdin.
// Hint: stdin is also nothing more (although slightly less) than a file
// but it is already open and you don't close it
// (but it may not exist at all, so check first)
/* Deleting all nodes of tree */
deltree(root);
fclose(fp);
fclose(outputfile);
return 0;
}
node *insertion(node * r, char *key, char *value)
{
if (r == NULL) // BST is not created created
{
r = (node *) malloc(sizeof(node)); // create a new node
// insert data to new node
strcpy(r->name, key);
strcpy(r->data, value);
// make left and right childs empty
r->left = NULL;
r->right = NULL;
}
// if the data is less than node value then we must put this in left sub-tree
else if (strcmp(key, r->name) < 0) {
r->left = insertion(r->left, key, value);
}
// else this will be in the right subtree
else if (strcmp(key, r->name) > 0) {
r->right = insertion(r->right, key, value);
} else {
if (strcmp(value, r->data) > 0) {
r->left = insertion(r->left, key, value);
} else if (strcmp(value, r->data) < 0) {
r->right = insertion(r->right, key, value);
}
// what if both, name and data are equal?
}
// if you don't want to do anything with the returned
// node than don't return it. Just an int indicating error
// or something in the line
return r;
}
void deltree(node * tree)
{
if (tree) {
deltree(tree->left);
deltree(tree->right);
free(tree);
}
}
// searching does not compare the same way as inserting
node *search(node ** tree, char *key, int count, FILE * fp_out)
{
if (!(*tree)) {
return NULL;
}
if (strcmp(key, (*tree)->name) < 0) {
search(&((*tree)->left), key, count, fp_out);
count++;
} else if (strcmp(key, (*tree)->name) > 0) {
search(&((*tree)->right), key, count, fp_out);
count++;
} else if (strcmp(key, (*tree)->name) == 0) {
// won't print anything, because you return before the printing
return *tree;
fprintf(fp_out, "%s --> %s\n", key, (*tree)->data);
} else {
fprintf(fp_out, "%s --> NOTFOUND", key);
}
printf("%s --> %s\n", key, count);
// nothing to return here?
}
// Thank you for the proper reference!
// Seems to grow less and less usual these times.
/*
* public domain strtok_r() by Charlie Gordon
*
* from comp.lang.c 9/14/2007
*
* http://groups.google.com/group/comp.lang.c/msg/2ab1ecbb86646684
*
* (Declaration that it's public domain):
* http://groups.google.com/group/comp.lang.c/msg/7c7b39328fefab9c
*/
char *strtok_r(char *str, const char *delim, char **nextp)
{
char *ret;
if (str == NULL) {
str = *nextp;
}
str += strspn(str, delim);
if (*str == '\0') {
return NULL;
}
ret = str;
str += strcspn(str, delim);
if (*str) {
*str++ = '\0';
}
*nextp = str;
return ret;
}
EDIT: the sketch. Please be aware that I didn't do all of your homework, I left a bit "for the student", as the saying goes.
/*
*
* - Construct a binary search tree to store the information contained in the file specified
* in the command line argument. Each record should be stored in a separate Node.
*
* - Search the binary search tree for records, based on their keys. The keys are read in
* from stdin, i.e. from the screen.
*
* For testing, it is often convenient to create a file of keys to be searched, one per line, and redirect the input from this file.
*
* Use the UNIX operator < for redirecting input from a file.
*
* - Examples of use:
* ./yelp1 datafile outputfile then type in keys;
* or
* ./yelp1 datafile outputfile < keyfile
*
* - Your program will look up each key and output the information (the data found) to the output
* file specified by the second command line parameter.
*
* If the key is not found in the tree,you must output the word NOTFOUND.
*
* The number of key comparisons performed during both successful and unsuccessful lookups
* have to be written to stdout.
*
* - Remember that the entries in the file do not necessarily have unique keys.
* Your search must locate all keys matching the search key, and output all the data found.
*/
/*
* Tested with datafile produced by the following shellcode
*
* # KEY "," DATA
* counter=1;
* while [ $counter -le 100 ];
* do counter=$((counter + 1));
* echo $(pwgen 10 1)","$(pwgen 10 1) >> testtree.db
* done;
*
* # ten random KEY
* shuf -n10 testtree.db | sed -e 's/,[a-z]\+//g' > testtree10keys
*
* # ten random DATA
* shuf -n10 testtree.db | sed -e 's/[a-z]\+,//g' > testtree10datas
*
* Please insert doublettes manually
*
*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
// data produced has only 10 characters each (plus NUL)
#define MAXNAMELENTH 11
#define MAXDATALENTH 11
typedef struct node {
char name[MAXNAMELENTH];
char data[MAXDATALENTH];
struct node *left;
struct node *right;
} node;
node *root;
node *search(node ** tree, char *key, int *count, FILE * fp_out);
int insertion(node ** r, char *key, char *value);
void deltree(node * tree);
//char *strtok_r(char *str, const char *delim, char **nextp);
void bt_print(node * leaf);
int main(int argc, char *argv[])
{
node *root;
// node *tmp;
FILE *fp;
FILE *outputfile;
// FILE *keyfile;
// FILE *fp_key;
// int i;
int counter = 0;
int bufsize = MAXDATALENTH + MAXNAMELENTH + 2;
// int keyfilelen = MAXNAMELENTH;
// char *keyread;
char *buffer;
// char *saveptr;
// char *line = NULL;
char *keyin = NULL;
char *valuein = NULL;
// char inputkey[MAXNAMELENTH];
// char *target_key = NULL;
// char *keyline = NULL;
char *e;
int res;
char *comma;
root = NULL;
// must have at least one argument
if (argc < 2) {
fprintf(stderr, "Usage: %s datafile [< key-list]\n", argv[0]);
exit(EXIT_FAILURE);
}
/* Inserting nodes into tree */
buffer = malloc(bufsize);
if (buffer == NULL) {
fprintf(stderr, "Malloc failed\n");
exit(EXIT_FAILURE);
}
fp = fopen(argv[1], "r");
if (fp == NULL) {
fprintf(stderr, "Opening \"%s\" for reading failed\n", argv[1]);
exit(EXIT_FAILURE);
}
outputfile = fopen("outputfile.txt", "a");
if (fp == NULL) {
fprintf(stderr, "Opening \"outputfile.txt\" for appending failed\n");
exit(EXIT_FAILURE);
}
while ((e = fgets(buffer, bufsize, fp))) {
if (e == NULL) {
if (ferror(fp)) {
// TODO: check errno for the exact kind of error
fprintf(stderr, "An eror occured during reading \"%s\"\n", argv[1]);
exit(EXIT_FAILURE);
} else if (feof(fp)) {
break;
}
}
// assuming strict KEY","DATA"\n" and without whitespace
// otherwise you need to check every step here!
// valuein points to the comma before DATA
valuein = strchr(buffer, ',');
// valuein points to DATA
valuein++;
// DATA is 10 characters large
valuein[10] = '\0';
// comma points to the comma before DATA
comma = strchr(buffer, ',');
// make *comma NUL
*comma = '\0';
keyin = buffer;
// ignoring return for now
//printf("%s,%s\n",keyin, valuein);
(void) insertion(&root, keyin, valuein);
}
bt_print(root);
// search-keys come from either stdin or get typed in.
// things typed in are also stdin
while ((res = scanf("%10s", buffer)) == 1) {
//printf("%s\n",buffer);
search(&root, buffer, &counter, outputfile);
printf("Misses for KEY \"%s\" = %d\n", buffer, counter);
counter = 0;
}
/* Deleting all nodes of tree */
deltree(root);
fclose(fp);
fclose(outputfile);
return 0;
}
void bt_print(node * leaf)
{
if (leaf) {
printf("%s,%s\n", leaf->name, leaf->data);
bt_print(leaf->left);
bt_print(leaf->right);
}
}
int insertion(node ** r, char *key, char *value)
{
if (*r == NULL) {
*r = malloc(sizeof(node));
if (r == NULL) {
return 0;
}
strcpy((*r)->name, key);
strcpy((*r)->data, value);
(*r)->left = NULL;
(*r)->right = NULL;
}
// Checks for returns omitted for clarity
else if (strcmp(key, (*r)->name) < 0) {
insertion(&(*r)->left, key, value);
}
// else this will be in the right subtree
else if (strcmp(key, (*r)->name) > 0) {
insertion(&(*r)->right, key, value);
} else {
if (strcmp(value, (*r)->data) > 0) {
insertion(&(*r)->left, key, value);
} else if (strcmp(value, (*r)->data) < 0) {
insertion(&(*r)->right, key, value);
}
// what if both, name *and* data are equal?
return 0;
}
return 1;
}
void deltree(node * tree)
{
if (tree) {
deltree(tree->left);
deltree(tree->right);
free(tree);
}
}
// search still cannot find multiple occurences of KEY
// Can you repair it?
node *search(node ** tree, char *key, int *count, FILE * fp_out)
{
node *tmp;
if (!(*tree)) {
printf("%s --> NOTFOUND\n", key);
fprintf(fp_out, "%s --> NOTFOUND", key);
return NULL;
} else {
if (strcmp(key, (*tree)->name) < 0) {
tmp = search(&((*tree)->left), key, count, fp_out);
(*count)++;
return tmp;
} else if (strcmp(key, (*tree)->name) > 0) {
tmp = search(&((*tree)->right), key, count, fp_out);
(*count)++;
return tmp;
} else {
// HINT 1: check (*tree)->left->name and (*tree)->right->name
// (recursively) and print it as long as key==name
// HINT 2: you don't need recursion, you can do it in a loop
printf("FOUND KEY %s --> DATA %s\n", key, (*tree)->data);
fprintf(fp_out, "%s --> %s\n", key, (*tree)->data);
return *tree;
}
}
}
I have a file with tab delimited data. I want to read the every line into a Structure. I have a code to read the data to char buffer. But I want to load the data into a Structure.
This is My sample data.
empname1\t001\t35\tcity1
empname2\t002\t35\tcity2
My Structure definition .
struct employee
{
char *empname;
char *empid;
int age;
char *addr;
};
My sample program to read data to a char array buffer
char buffer[BUF_SIZE]; /* Character buffer */
input_fd = open (fSource, O_RDONLY);
if (input_fd == -1) {
perror ("open");
return 2;
}
while((ret_in = read (input_fd, &buffer, BUF_SIZE)) > 0){
// Do Some Process
}
Here I want to load the content to a structure variable instead of the character buffer. How I can achieve that?
Well, a possible solution could be
Read a complete line from the file using fgets().
tokenize the input buffer based on the required delimiter [tab in your case] using strtok().
allocate memory (malloc()/ realloc()) to a pointer variable of your structure.
copy the tokenized inputs into the member variables.
Note:
1. fgets() reads and stores the trailing \n.
2. Please check carefully how to use strtok(). The input string should be mutable.
3. Allocate memory to pointers before using them. IMO, use statically allocated array as struct employee member variables.
You can use the fscanf function. Open a file as a stream then use the fscanf to get a input from the file.
int fscanf(FILE *stream, const char *format, ...);
FILE *fp=fopen(fsource,"r+");
struct employee detail;
fscanf(fp,"%s %s %d %s",detail.empname,detail.empid,&detail.age,detail.addr);
Make sure that allocation of memory to the variables.
Or else you can use the strtok function. That time you have to use the sscanf function.
You can use fscanf to read each line from file, strtok to tokenize the line read.
Since your structure members are pointers, allocate memory appropriately.
The following minimal code does exactly what you want.
#define SIZE 50
FILE *fp = NULL;
int i = 0;
struct employee var = {NULL, NULL, 0, NULL};
char line[SIZE] = {0}, *ptr = NULL;
/* 1. Open file for Reading */
if (NULL == (fp = fopen("file.txt","r")))
{
perror("Error while opening the file.\n");
exit(EXIT_FAILURE);
}
/* 2. Allocate Memory */
var.empname = malloc(SIZE);
var.empid = malloc(SIZE);
var.addr = malloc(SIZE);
/* 3. Read each line from the file */
while (EOF != fscanf(fp, "%s", line))
{
/* 4. Tokenise the read line, using "\" delimiter*/
ptr = strtok(line, "\\");
var.empname = ptr;
while (NULL != (ptr = strtok(NULL, "\\")))
{
i++;
/* 5. Store the tokens as per structure members , where (i==0) is first member and so on.. */
if(i == 1)
var.empid = ptr;
else if(i == 2)
var.age = atoi(ptr);
else if (i == 3)
var.addr = ptr;
}
i = 0; /* Reset value of i */
printf("After Reading: Name:[%s] Id:[%s] Age:[%d] Addr:[%s]\n", var.empname, var.empid, var.age, var.addr);
}
Working Demo: http://ideone.com/Kp9mzN
Few things to Note here:
This is guaranteed to work, as long as your structure definition (and order of members) remains the same (see manipulation of value i).
strtok(line, "\\");, Second argument is just escaping (first \) the actual \ character.
Clarification from the OP:
In your structure definition, third member is an int, however you're trying to read t35 into it (which is a string).
So var.age = atoi(ptr); will give you 0,
You could change the structure definition, making third member as char * and allocating memory like other members.
Or change file contents, making sure an int is present as the third value.
I think this may be what you are looking for
#include <string.h>
#include <stdio.h>
#include <stdlib.h>
#include <stdbool.h>
#include <unistd.h>
#include <fcntl.h>
#include <sys/stat.h>
struct employee
{
char *empname;
char *empid;
int age;
char *addr;
};
int readEmploee(char *line, struct employee *employee)
{
char *token;
char *saveptr;
char *endptr;
if ((employee == NULL) || (line == NULL))
return 0;
token = strtok_r(line, "\t", &saveptr);
if (token == NULL)
return 0;
employee->empname = strdup(token);
token = strtok_r(NULL, "\t", &saveptr);
if (token == NULL)
return 0;
employee->empid = strdup(token);
token = strtok_r(NULL, "\t", &saveptr);
if (token == NULL)
return 0;
employee->age = strtol(token, &endptr, 10);
if (*endptr != '\0')
return 0;
token = strtok_r(NULL, "\t", &saveptr);
if (token == NULL)
return 0;
employee->addr = strdup(token);
return 1;
}
char *mygetline(int fd)
{
char *line;
size_t length;
size_t count;
char character;
line = malloc(128);
if (line == NULL)
return NULL;
length = 0;
count = 1;
do
{
if (read(fd, &character, 1) != 1) /* end of file probably reached */
{
free(line);
return NULL;
}
else if (character != '\n')
{
if (length > 128 * count)
{
char *temp;
temp = realloc(line, 128 * count);
if (temp == NULL)
{
free(line);
return NULL;
}
line = temp;
count += 1;
}
line[length++] = character;
}
} while (character != '\n');
line[length] = 0;
return line;
}
struct employee *readFile(const char *const fSource, size_t *count)
{
struct employee *employees;
int employeeCount;
int input_fd;
char *line;
if ((count == NULL) || (fSource == NULL))
return NULL;
*count = 0;
employees = NULL;
employeeCount = 0;
input_fd = open (fSource, O_RDONLY);
if (input_fd == -1)
{
perror ("open");
return NULL;
}
while ((line = mygetline(input_fd)) != NULL)
{
struct employee employee;
if (readEmploee(line, &employee) != 0)
{
struct employee *temp;
temp = realloc(employees, (1 + employeeCount) * sizeof(struct employee));
if (temp != NULL)
employees = temp;
employees[employeeCount++] = employee;
}
free(line);
}
*count = employeeCount;
return employees;
}
int
main()
{
size_t count;
size_t index;
struct employee *employees;
employees = readFile("somesamplefile.txt", &count);
if (employees == NULL)
return 1;
for (index = 0 ; index < count ; index++)
{
struct employee current;
current = employees[index];
fprintf(stderr, "%s, %s, %d, %s\n", current.empname, current.empid, current.age, current.addr);
if (current.empname != NULL)
free(current.empname);
if (current.empid != NULL)
free(current.empid);
if (current.addr != NULL)
free(current.addr);
}
free(employees);
return 0;
}
I want to put each line in a text file in a node in a linked list. I have managed to write out the text line by line, but when I try to store the line in a node, only the last line of the text is saved in all the nodes. Any idea what I'm doing wrong?
#include <stdio.h>
#include <stdlib.h>
struct list
{
char *line;
struct list *next;
};
int main(void)
{
FILE *f;
f = fopen("text.txt", "r");
if (f == NULL) exit("ERROR\n");
struct list n1, n2, n3, n4;
struct list *pointer = &n1;
n1.line = NULL;
n1.next = &n2;
n2.line = NULL;
n2.next = &n3;
n3.line = NULL;
n3.next = &n4;
n4.line = NULL;
n4.next = 0;
int nodenr = 0;
int buf[50];
while(fgets(buf, sizeof(buf), f) != NULL)
{
printf("%s", buf);
++nodenr;
if (nodenr == 1)
{
n1.line = buf;
}
else if (nodenr == 2)
{
n2.line = buf;
}
else if (nodenr == 3)
{
n3.line = buf;
}
else if (nodenr == 4)
{
n4.line = buf;
}
}
while (pointer != 0)
{
printf("%s\n", pointer->line);
pointer = pointer->next;
}
fclose(f);
}
Your problem occurs because all your nodes' line pointer point to the buf buffer, so all will have the last line you read into it.
You have to assign a copy of the buffer for each node when you read it, not the buffer pointer itself.
I maybe have a problem
buf is pointer, so if you change value in fgets, then it change everywhere...
But in this case there should be the last line everywhere...
I am not so good in C programming, so sorry if it is bad answer
This question is unlikely to help any future visitors; it is only relevant to a small geographic area, a specific moment in time, or an extraordinarily narrow situation that is not generally applicable to the worldwide audience of the internet. For help making this question more broadly applicable, visit the help center.
Closed 10 years ago.
Doing a homework and I'm having problems with, what I believe, pointers.
The assignment consists in the following:
I have a txt file where each line as a name and a password.
thisismyname:thisismypassword
I have to read this data, process it into struct linked list, run all the list and send the password to a brute-force algorithm. This algorithm, after finding the pass, should write the pass on the struct. In the end, I should run the list and write the data to a txt file
My problem is when I find the password. It is not storing its value in the struct. At the end I can read the data, I can see that the brute-force is working but at the end, I'm only managing to write the name and pass to file. The unencrypted pass is being written as NULL so I believe is a pointer problem.
This is the code (Removed all the things that I believe are irrelevant):
typedef struct p {
char *name;
char *pass;
char *pass_desenc;
struct p *next_person;
} person;
typedef struct n {
int a;
int b;
} numbers;
int readFile(person **people) {
FILE * fp;
char line[100];
if ((fp = fopen(STUDENTS_FILE, "r")) != NULL) {
while (fgets(line, sizeof (line), fp) != NULL) {
person *p;
char email[27] = "";
char password[14] = "";
char *change = strchr(line, '\n');
if (change != NULL)
*change = '\0';
/* Gets email*/
strncpy(email, line, 26);
email[27] = '\0';
/* Gets pass*/
strncpy(password, line + 27, 14);
password[14] = '\0';
p = (person*) malloc(sizeof (person));
if (p == NULL) {
return -1;
}
p->name = (char*) malloc(strlen(email));
if (p->name == NULL) {
return -1;
}
sprintf(p->name, "%s", email);
p->name[strlen(email)] = '\0';
p->pass = (char*) malloc(strlen(password));
if (p->pass == NULL) {
return -1;
}
sprintf(p->pass, "%s", password);
p->pass[strlen(password)] = '\0';
p->next_person = (*people);
(*people) = p;
countPeople++;
}
fclose(fp);
return 0;
}
return -1;
}
void fmaps(int id, numbers pass_range, person *people) {
/*This function will run all my list and try to uncrypt pass by pass.
On the brute-force pass in unencrypted and when it return to this function, I can print the data.
*/
while (people != NULL && j > 0) {
for (i = 1; i <= PASS_SIZE && notFound == 1; i++) {
notFound = bruteForce(i, people, &total_pass);
}
notFound = 1;
count = count + total_pass;
printf("#####Email: %s Pass: %s PassDesenq: %s \n", people->name, people->pass, people->pass_desenc);
people = people->next_person;
j--;
}
}
void fcontrol(int n, person *people) {
/*This function should write the data to a file
I can see that all data is written as expected but people->pass_desenc is writing/printing NULL
*/
if ((fp = fopen(STUDENTS_LOG_FILE, "a+")) != NULL) {
while (people != NULL) {
printf("#####1111Email: %s Pass: %s PassDesenq: %s \n", people->name, people->pass, people->pass_desenc);
fprintf(fp, "%d%d%d%d%d%d:grupo%d:%s:%s\n", tm.tm_year + 1900, tm.tm_mon + 1, tm.tm_mday, tm.tm_hour, tm.tm_min, tm.tm_sec, 1, people->name, people->pass_desenc);
people = people->next_person;
}
}
fclose(fp);
}
int main() {
/*Struct*/
person *people = NULL;
if (readFile(&people)) {
printf("Error reading file!\n");
return 0;
}
/*Function to send data to brute-force*/
fmaps(i, pass_range, people);
/*After all data is processed, this function writes the data to a file*/
fcontrol(NR_PROC, people);
destroyList(&people);
return 0;
}
int bruteForce(int size, person *people, int *total_pass) {
int i;
char *pass_enc;
int *entry = (int*) malloc(sizeof (size));
char pass[50];
char temp;
pass[0] = '\0';
for (i = 0; i < size; i++) {
entry[i] = 0;
}
do {
for (i = 0; i < size; i++) {
temp = (char) (letters[entry[i]]);
append(pass, temp);
}
(*total_pass)++;
/*Compare pass with test*/
pass_enc = crypt(pass, salt);
if (strcmp(pass_enc, people->pass) == 0) {
people->pass_desenc = (char*) malloc(strlen(pass));
if (people->pass_desenc == NULL) {
return -1;
}
sprintf(people->pass_desenc, "%s", pass);
people->pass_desenc[strlen(pass)] = '\0';
return 0;
}
pass[0] = '\0';
for (i = 0; i < size && ++entry[i] == nbletters; i++) {
entry[i] = 0;
}
} while (i < size);
free(entry);
return 1;
}
void append(char *s, char c) {
int len = strlen(s);
s[len] = c;
s[len + 1] = '\0';
}
void destroyList(person **people) {
person *aux;
printf("\nList is being destroyed.");
while (*people != NULL) {
aux = *people;
*people = (*people)->next_person;
free(aux);
printf(".");
}
printf("\nList destroyed.\n");
}
I believe that the changes being made in fmaps are local and are not passing to main.
Any help is appreciated...
This is how you could code the file reader/parser. It avoids str[n]cpy(), and does all string operations using memcpy() + the offsets + sizes. (which need to be correct in both cases, obviously)
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <errno.h>
typedef struct p {
char *name;
char *pass;
// char *pass_desenc;
struct p *next;
} person;
#define STUDENTS_FILE "students.dat"
unsigned countPeople = 0;
int readFile(person **people) {
FILE * fp;
char line[100];
size_t len, pos;
fp = fopen(STUDENTS_FILE, "r");
if (!fp) {
fprintf(stderr, "Could not open %s:%s\n"
, STUDENTS_FILE, strerror(errno));
return -1;
}
while ( fgets(line, sizeof line, fp) ) {
person *p;
len = strlen(line);
/* remove trailng '\n', adjusting the length */
while (len && line[len-1] == '\n') line[--len] = 0;
/* Ignore empty lines */
if ( !len ) continue;
/* Library function to count the number of characters in the first argument
** *not* present in the second argument.
** This is more or less equivalent to strtok(), but
** 1) it doen not modify the string,
** 2) it returns a size_t instead of a pointer.
*/
pos = strcspn(line, ":" );
/* Ignore lines that don't have a colon */
if (line[pos] != ':') continue;
p = malloc(sizeof *p);
if ( !p ) { fclose(fp); return -2; }
p->next = NULL;
p->name = malloc(1+pos);
if ( !p->name ) { fclose(fp); return -3; } /* this could leak p ... */
memcpy(p->name, line, pos-1);
p->name[pos] = 0;
p->pass = malloc(len-pos);
if ( !p->pass ) {fclose(fp); return -4; } /* this could leak p and p->name */
memcpy(p->pass, line+pos+1, len-pos);
/* Instead of pushing (which would reverse the order of the LL)
** , we append at the tail of the LL, keeping the original order.
*/
*people = p;
people = &p->next ;
countPeople++;
}
fclose(fp);
return 0;
}