Using fgets to read a .CSV file - c

I have already googled a lot about this, but I want to know one thing. I have a .csv file that I need to read, pass to a struct with linked list. The lines of file doesn't have the same size.
I'm thinking use fgets() to read each line, and then use strtok to get info through "," and pass to struct.
I'M USING LINUX.
typedef struct nodo
{
int row1;
char row2;
int row3;
struct nodo *next;
struct nodo *nant;
}nodo;
nodo* insert_last(nodo* base1, nodo* nv)
{
if(base1 == NULL)
base1 =nv;
base1->next = NULL;
while(base1->next != NULL)
base1 = base1->next;
base1->next = nv;
nv->nant = base1;
nv->next = NULL;
}
nodo* put2memory(nodo *base1)
{
nodo *nv;
FILE *fp1=fopen(xxx,"r");
char *tok;
while(fgets((buffer, sizeof(buffer),fp1) != NULL))
{
nv = (nodo*) malloc (sizeof(nodo));
nv->next=NULL;
tok = strtok(buffer,",");
nv->row1=tok;
tok = strtok(NULL,",");
nv->row2=tok;
tok = strtok(NULL,",");
nv->row3=tok;
insert_last(base1,nv);
}
free(nv);
}
int main()
{
nodo *base1;
put2memory(base1);
return 0;
}
I'm thinking doing like that but i'm returning "my friend" segmentation fault!!
SYNTAX FILE :
123,abc,23
23,d,444
.
.
.

insert_last doesn't look good to me for the case where base1 is null.
nodo* insert_last(nodo* base1, nodo* nv)
{
if(base1 == NULL)
base1 =nv;
At minimum I would put return nv here. Without that, what your code does is set nv->next to nv. (Or rather try to insert nv after base1 which will be set after `nv.)
As a broader point, note that your insert_last is O(n) since it must find the end of the list before inserting. This means inserting N elements is O(N2). A decent linked list implementation will track the tail element in memory and insert in constant time.
Update: read the rest of the code. This is also invalid:
nodo *base1;
put2memory(base1);
base1 has not been initialized and is a garbage value at this point. You're trying to use it as pointer.
Here's one suggestion for how to fix it:
Add return statements to insert_last. I suggest returning the head of the list. Even better would be to store both head and tail and avoid O(N) inserts.
Change your call to insert_last to do something like:
list_head = insert_last(base1,nv);
In main, you can do something like:
list_head = put2memory(NULL);
Update again: To illustrate O(1) insertion, here's an adjustment of your put2memory. Note that you'd eventually have to call free() on every list node.
nodo* put2memory()
{
nodo *head = NULL, *prev = NULL, *nv;
FILE *fp1=fopen(xxx,"r");
char *tok;
while(fgets((buffer, sizeof(buffer),fp1) != NULL))
{
nv = (nodo*) malloc (sizeof(nodo));
nv->next=NULL;
tok = strtok(buffer,",");
nv->row1=tok;
tok = strtok(NULL,",");
nv->row2=tok;
tok = strtok(NULL,",");
nv->row3=tok;
if (prev)
prev = prev->next = nv;
else
head = prev = nv;
}
return head;
}

Related

Why aren't new elements being added to my linked list?

This is just a snippet of the code, but I checked and know for a fact that all the strings save nicely into the "new" element (in function SortedInsert), but then the "new" doesn't link to the head?
I've tried everything I could think, hopefully I'm just missing something obvious.
typedef struct _Info* Position;
typedef struct _Info{
char name[MAX];
char surname[MAX];
Position next;
} Info;
(declaration inside main function:
Info headInfo = {.name = {0}, .surname {0}, .next = NULL};
Position head = &headInfo;
)
int SortedInsert(Position head, char name[], char surname[]){
Position prev = NULL, temp = NULL, new = NULL;
prev = head;
temp = head->next;
new = (Position)malloc(sizeof(Info));
if(!new){
return EXIT_FAILURE;
}
strcpy(new->name, name);
strcpy(new->surname, surname);
new->next = NULL;
if(head->next==NULL){
temp = new;
}
else{
// first sort, by surname
while(strcmp(temp->surname, new->surname) < 0){
prev = temp;
temp = temp->next;
}
// second sort, by name
while(strcmp(temp->name, new->name) < 0){
prev = temp;
temp = temp->next;
}
new->next = prev->next;
prev->next = new;
}
return EXIT_SUCCESS;
}
int PrintList(Position head){
Position temp = NULL;
temp = head->next;
while(temp){
printf("%s ", temp->name);
printf("%s\n", temp->surname);
printf("---\n");
temp = temp->next;
}
return EXIT_SUCCESS;
}
Some issues:
temp = new does not insert anything into the list. It merely copies a reference to the new node into a local variable. The assignment should be to head->next. Moreover, there is no need to create a separate case for this. It can be handled with the code you have in the else part.
The retrieval of the insert point is not correct. If in the first loop the strcmp call returns 1 (not 0), then the second while loop should not iterate at all: it doesn't matter in that case what the first name is like. The last name of temp is already greater, so the insertion point has been found. Similarly, if the strcmp call returns 0, the second loop should keep verifying that the last name is still the same in its second iteration,...etc. Moreover, this logic can be combined in one loop.
Not a problem for the correct execution, but still:
Many consider it bad practice to typedef a pointer to a struct where you dereference the pointer regularly in your code. See the answers to Is it a good idea to typedef pointers? for some background. So I'd keep using Info *.
Create a separate function for creating and initialising a node.
The comments that say "first sort", "second sort" are misleading. There is no sorting happening in the loop that follows the comment. The list is already sorted. The process that follows just intends to find the insertion spot according to the sort order. So the comment could be improved.
Many consider it better not to cast the value returned by malloc.
Here is the correction of the SortedInsert function, together with the separated function for node creation:
Info *createNode(char name[], char surname[]) {
Info *new = malloc(sizeof(*new));
if (new != NULL) {
strcpy(new->name, name);
strcpy(new->surname, surname);
new->next = NULL;
}
return new;
}
int SortedInsert(Info *head, char name[], char surname[]){
Info *new = createNode(name, surname);
if (new == NULL) {
return EXIT_FAILURE;
}
Info *prev = head;
Info *temp = head->next;
// Find insertion spot according to sort order
while (temp != NULL) {
int cmp = strcmp(temp->surname, new->surname);
if (cmp == 0) { // It's a tie. Then use name as discriminator
cmp = strcmp(temp->name, new->name);
}
if (cmp >= 0) { // Found insertion spot
break;
}
prev = temp;
temp = temp->next;
}
new->next = prev->next;
prev->next = new;
return EXIT_SUCCESS;
}

Array pointer always points to NULL

Im trying create a linked list in an array of nodes. When I try to update the pointer for arrTab->h_table[index] to the address of newNode, The address points to newNodes address. But when I try to add to a list that exists in the array, the pointer always points to NULL instead of the previous value in memory. Basically the arrTab->h_table[index] head of the linked list does not update to the address of newNode.
typedef struct node {
struct node* next;
int hash;
s_type symbol;
} node_t;
struct array {
int cap;
int size;
n_type** h_table;
};
int add_to_array (array* arrTab, const char* name, int address) {
if(s_search(arrTab, name, NULL, NULL) == NULL){
s_type *symbol = (s_type*) calloc(1, sizeof(s_type));
symbol->name = strdup(name);
symbol->addr = addr;
n_type *newNode = (n_type*) calloc(1, sizeof(n_type));
newNode->next = NULL;
newNode->hash = nameHash(name);
newNode->symbol = *symbol;
int index = newNode->hash % arrTab->cap;
if(arrTab->h_table[index] == NULL){
arrTab->h_table[index] = newNode;
} else {
newNode->next = arrTab->h_table[index];
arrTab->h_table[index] = newNode;
}
//
arrTab->size++;
return 1;
}
return 0;
}
struct node* s_search (array* arrTab, const char* name, int* hash, int* index) {
int hashVal = nameHash(name);
hash = &hashVal;
int indexVal = *hash % arrTab->cap;
index = &indexVal;
s_type *symCopy = arrTab;
while (symCopy->h_table[*index] != NULL){
if(*hash == symCopy->h_table[*index]->hash){
return symCopy->h_table[*index];
}
symCopy->h_table[*index] = symCopy->h_table[*index]->next;
}
return NULL;
}
I cannot say for sure why the pointer always points to NULL; there is not enough code. Consider posting an MCVE.
The posted code however presents few problems to address.
First, it leaks memory like there is no tomorrow:
symbol_t *symbol = (symbol_t*) calloc(1, sizeof(symbol_t));
allocates some memory, and
newNode->symbol = *symbol;
copies the contents of that memory to the new location. The memory allocated still exists, and continues to exist after the function returns - but there's no way to get to it. I strongly recommend to not allocate symbol, and work directly with newNode->symbol:
newNode->symbol.name = strdup(name);
newNode->symbol.addr = addr;
The hash and index parameters to symbol_search seem to be planned as an out parameters. In that case, notice that the results of hash = &hashVal; and index = &indexVal; are invisible to the caller. You likely meant *hash = hashVal and *index = indexVal.
The biggest problem comes with sym_table_t *symCopy = symTab;.
symTab is a pointer. It points to an actual symbol table, a big piece of memory. After the assignment, symCopy points to the same piece of memory. Which means that
symCopy->hash_table[*index] = symCopy->hash_table[*index]->next;
modifies that piece of memory. Once the search is completed, the hash_table[index] is not the same as it was before the search. This could be a root of your problem. In any case, consider
node_t * cursor = symTab->hash_table[*index];
and work with this cursor instead.
As a side note, a search condition *hash == symCopy->hash_table[*index]->hash is strange. Every node in a given linked list has the same hash (check how you add them). The very first node would produce a match, even if the names are different.

C - Read file to Doubly Linked List got segmentation fault

I am reading from txt file into a doubly linked list. The codes can do storing data into Nodes, but when I let it go through the linked list, it got a segmentation fault.
Could you guys please tell what has been wrong with the code, thank you!
This is the data structure:
typedef struct telephoneBookNode {
int id;
char name[NAME_LENGTH];
char telephone[TELEPHONE_LENGTH];
struct telephoneBookNode * previousNode;
struct telephoneBookNode * nextNode;
} TelephoneBookNode;
typedef struct telephoneBookList {
TelephoneBookNode * head;
TelephoneBookNode * tail;
TelephoneBookNode * current;
unsigned size;
} TelephoneBookList;
This is the code to create linked list:
TelephoneBookList * createTelephoneBookList(char entry[]) {
TelephoneBookList* aList = NULL;
TelephoneBookNode* aNode = NULL;
char *tokens;
TelephoneBookNode *(*create)() = createTelephoneBookNode;
aNode = (*create)();
tokens = strtok(entry, ", ");
aNode->id = atoi(tokens);
tokens = strtok(NULL, ", ");
strcpy(aNode->name, tokens);
tokens = strtok(NULL, ", ");
strcpy(aNode->telephone, tokens); //Fine until here
//Do I need this line?
//aList = (TelephoneBookList*) malloc(aList->size + 1) * sizeof aList);
if (aList->head == NULL) {
aNode->nextNode = NULL;
aNode->previousNode = NULL;
aList->current = aNode;
aList->head = aNode;
aList->tail = aNode;
} else {
aList->tail->nextNode = aNode;
aNode->previousNode = aList->tail;
}
return aList;
}
TelephoneBookNode * createTelephoneBookNode() {
TelephoneBookNode* aNode;
aNode = (TelephoneBookNode*) malloc(sizeof *aNode);
return aNode;
}
//Do I need this line?
//aList = (TelephoneBookList*) malloc(aList->size + 1) * sizeof aList);
Yes. Yes you do need that line. Otherwise the next line
if (aList->head == NULL) {
will dereference a null pointer.
Though you already do that in the commented out malloc call, dereference a null pointer, with aList->size + 1.
The correct line should be
aList = malloc(sizeof *aList);
And since you create the list from scratch in the function, there is no need to check if it is empty or not, it will always be empty. More importantly, the malloc call will not initialize the memory it allocates, so using that memory (for example in an expression like aList->head == NULL) will lead to undefined behavior.
Allocate the list structure. And then initialize it as if it was empty. And don't forget to initialize the size member as well.
Your createTelephoneBookNode function does not initialize the node that it created. malloc() assigns it a memory block that's probably not been initialized with zeros, and as a result, the nextNode and previousNode pointers contain garbage. Either set them both to NULL, or allocate your memory with calloc().

invalid write size of 1 in C

I trying to write a queue(String Version) program in C by using linked lists.
Here is the structure:
struct strqueue;
typedef struct strqueue *StrQueue;
struct node {
char *item;
struct node *next;
};
struct strqueue {
struct node *front;//first element
struct node *back;//last element in the list
int length;
};
I creates a new StrQueue first
StrQueue create_StrQueue(void) {
StrQueue q = malloc(sizeof (struct strqueue));
q->front = NULL;
q->back = NULL;
q->length = 0;
return q;
}
makes a copy of str and places it at the end of the queue
void push(StrQueue sq, const char *str) {
struct node *new = malloc(sizeof(struct node));
new->item = NULL;
strcpy(new->item,str);//invalid write size of 1 ?
new->next = NULL;
if (sq->length == 0) {
sq->front = new;
sq->back = new;
} else {
sq->back->next = new;
sq->back = new;
}
sq->length++;
}
frees the node at the front of the sq and returns the string that was first in the queue
char *pop(StrQueue sq) {
if (sq->length == 0) {
return NULL;
}
struct node *i = sq->front;
char *new = sq->front->item;
sq->front = i->next;
sq->length --;
free(sq->front);
return new;
}
I got invalid write size of 1 at strcpy(new->item,str); I dont understand why I got this error.
Can anyone tell me why and tell me how should I fix it? Thanks in advance.
Okay, first things first, in the answer below I am NOT fixing your doubly linked list concepts, I am just showing you how you should fix the code above within the scope of your question. You may want to look into how doubly linked lists are done.
In:
void push(StrQueue sq, const char *str) {
struct node *new = malloc(sizeof(struct node));
new->item = NULL;
The next statement is wrong:
strcpy(new->item,str);
There are two ways you can solve it:
Make sure that *str is a valid pointer outside of the list management context while the list is being used.
Let the list manage the string allocation (and possibly deallocation).
is the quick and dirty method, it's easier to debug later but larger codebase makes it cumbersome.
cleaner looking code, but requires initial setup discipline, you should create object (string) management routines in addition to list management routines. can be cumbersome in its own right.
CASE 1: const char *str is guaranteed to be valid for life of StrQueue (this is what you are looking for really)
It should be:
new->item = str;
Here we assume str was a dynamic string allocated elsewhere
Now, in pop when you pop off the string you are okay. because the pointer you are returning is still valid (you are guaranteeing it elsewhere)
CASE 2: const char *str is not guaranteed to be valid for life of StrQueue
Then use:
new->item = strdup(str);
Now, in pop when you pop off the string you can either
de-allocate the strdup and not return anything, (not quite the same things as you did)
pass a container pointer to pop where contents of item are copied (clean)
return the popped off pointer, but you must deallocate it separately when you are done with it (ugly)
Which would make your pop function one of the following:
Case 2.1:
void pop(StrQueue sq) {
if (sq->length == 0) {
return NULL;
}
struct node *node = sq->front;
sq->front = node->next;
sq->length--;
free(node->item);
free(node);
}
Case 2.2:
char *pop(StrQueue sq, char *here) {
if (sq->length == 0) {
return NULL;
}
struct node *node = sq->front;
sq->front = node->next;
sq->length--;
strcpy(here, node->item);
free(node->item);
free(node);
}
Case 2.3:
char *pop(StrQueue sq) {
char *dangling_item = NULL;
if (sq->length == 0) {
return NULL;
}
struct node *node = sq->front;
sq->front = node->next;
sq->length--;
dangling_item = node->item;
free(node);
return dangling_item;
}
I got invalid write size of 1 at strcpy(new->item,str); I dont understand why I got this error. Can anyone tell me why and tell me how should I fix it?
Why:
This code:
new->item = NULL;
strcpy(new->item,str);//invalid write size of 1 ?
You're not suppose to pass a null pointer to the first argument, it should be a pointer to allocated memory. The reason why you're getting this error message, I can imagine, is because the implementation of strcpy probably looks like this:
for (int i = 0; str2[i]; i++) str1[i] = str2[i];
And in the first iteration of the for loop, it writes to address 0 (a read-only section of memory) - this gives you the invalid write of size 1. I'm not sure, however, why you are only getting a size of 1, though (I would imagine it would be the entire size of the string). This could be because either a) str is only of size 1 or b) because the signal, SIGSEGV stops the program.
How to fix:
Allocate space for new->item before calling strcpy, like this:
new->item = malloc (strlen (str) + 1); // + 1 for null-terminating character
But you could probably include some error checking, like this:
int len = strlen (str) + 1;
if (len){
new->item = malloc (len);
if (!new->item){
return;
}
}

Linked List Insertion & Selection

I define a linked list in the same way as it is commonly used, i.e. with a data part and a
self referencing pointer. My logic of insertion is as follows:
struct node
{
int data; //or any type.
struct node *nextPtr;
}*start = NULL;
//main
struct *newPtr = (struct node *)malloc(sizeof(struct node *));
scanf("%d", newPtr->data); //or cout
newPtr->nextPtr = NULL;
if(start == NULL)
start = newPtr;
else
{
while(tempPtr->nextPtr != NULL)
{
tempPtr = tempPtr->nextPtr;
}
tempPtr->nextPtr = newPtr;
}
i) Is this logic correct?
ii) a) I possibly get a run-time error, when I insert two nodes (in one system) or three nodes(in another).
b) The nodes are inserted in the correct order, every time I insert a node.
Is the run-time error as a result of this code...???
struct node
{
int data; //or any type.
struct node *nextPtr;
}*start = NULL;
//main
struct *newPtr = (struct node *)malloc(sizeof(struct node));// You dont need * here
scanf("%d", newPtr->data); //or cout
newPtr->nextPtr = NULL;
if(start == NULL)
start = newPtr;
else
{
tempPtr = start; // you missed this.
while(tempPtr->nextPtr != NULL)
{
tempPtr = tempPtr->nextPtr;
}
tempPtr->nextPtr = newPtr;
}
disregard the answer as it is c++, the original question was tagged c++
The original code, once the small issues are solved (actual allocation of the node, setting the value, definition of the temporary pointer to help walk the list) should work. But there are other approaches that you can take to simplify the code (well, not that it is hugely complex), which basically imply finding the point of insertion before creation first then creating the new element:
Node** insertPoint = &start;
while (*insertionPoint)
insertionPoint = &((*insertionPoint)->next);
*insertionPoint = new Node(value);
Use a pointer to pointer to walk through the list, initialized with the address of the head pointer move it until it refers to the Node* where the new element will be appended (note, appended, not inserted). Then create the new node in that position. This assumes that the Node constructor takes care of copying the value and initializing the next pointer.
Alternatively you can write this recursively and let the compiler perform the tail optimization for you (it might be a bit simpler to read, some people find recursion simpler, some don't):
void append( Node*& tail, Value value ) {
if ( tail==NULL )
list = new Node(value);
else
append( list->next, value );
}
Calling code:
append( start, 100 ); // assuming nits contained in the list
In this case, instead of a double pointer we can use a reference to the pointer, as we don't need to modify it
struct node *newPtr, **hnd;
newPtr = malloc(sizeof *newPtr);
if (!newPtr) barf();
scanf("%d", &newPtr->data);
newPtr->nextPtr = NULL;
for(hnd = &start; *hnd; hnd = &(*hnd)->next) {;}
*hnd = newPtr;

Resources