C - Problems copying string from one struct to a node - c

I am trying to copy strings from a field in one struct to another struct (a node), so that I can ultimately create a hashtable. However, I seem to be having some issues in the actual string copying. I've created a for loop to iterate over the strings in the source stuct, and I know the iteration is working fine, because if I printf the source strings (data[i].c_name), they print out fine. Unfortunately, when I try to printf the destination (class_id), it seems to be empty (and thus of course my hash function isn't doing much). Any insights into the potential problem here would be greatly appreciated. Please let me know if I haven't given enough context.
#define LENGTH 30
#define MAX_OBS 80000
typedef struct
{
char c_name[LENGTH];
char s_name[LENGTH];
double value[MAX_OBS];
}
sample;
typedef struct node
{
char class_id[LENGTH];
struct node *next;
}
node;
{
char class_id[LENGTH];
for (int i = 0; i < total_columns; i++)
{
// malloc a new node pointer for each new class label
node *new_node = malloc(sizeof(node));
// check that there was sufficient memory
if (new_node == NULL)
{
return 6;
}
// copy c_name into node -- failing - class_id is empty
strcpy(new_node->class_id, data[i].c_name);
printf("%s\n", class_id);
}
}

Drop the last char class_id[LENGTH]; that you print as it was never initialized. Then switch your printf() to use the actual target of the strcpy.
strncpy(new_node->class_id, data[i].c_name, LENGTH);
printf("%.*s\n", LENGTH, new_node->class_id);
I've also put a few LENGTH limits in my code to assure you don't do bad things on bad input without a terminal \0. Never blindly trust your C input unless you generated it in a fail-safe manner.
Disclaimer: desktop inspection changes. Actual debugging is left as an exercise to the student.

Related

how to allocate memory to array of pointers?

i have been given a structure and a pointer to an array.
each index of the array is a letter of the alphabet. i need to receive a name, last name and phone number, and allocate memory to a struct (phonebook).
then, each struct needs to be accessed from the array using the last name's first letter.
if the function is called again i need to use linked list to add another contact.
i dont know how to allocate memory for a certain index of an array. when i try to do
phonebook[letter] = (Contact**)malloc(sizeof(Contact));
i keep having de reference warnings, and i cant seem to figure out how to point the address of phonebook[letter] to a structure properly.
this is what i have tried:
typedef struct Contact {
char* firstName;
char* lastName;
char* phoneNum;
struct Contact* next;
} Contact;
int main(){
Contact* phonebook[26];
addNewContact(phonebook)
}
int addNewContact(Contact** phonebook) {
char newFirstName[SIZE], newLastName[SIZE], newPhoneNum[SIZE];
int letter;
printf("Enter a contact details \
(<first name> <last name> <phone number>):\n");
scanf("%s%s%s", newFirstName, newLastName, newPhoneNum);
//get number of the letter in the alphabet
letter = newLastName[0] - 'A';
//allocate memory to pointer
Contact *current;
phonebook = (Contact**)malloc(sizeof(Contact));
if (phonebook == NULL) {
printf("The addition of the contact has failed!");
//free
exit(1);
}
current = phonebook[letter];
//check if details are being used
do {
//if the name already exists
if (phonebook[letter]->firstName == newFirstName \
&& phonebook[letter]->lastName == newLastName) {
printf("The addition of the contact has failed, \
since the contact %s %s already exists!\n", newFirstName, newLastName);
//free
return 0;
}
//if the phone number already exists
if (phonebook[letter]->phoneNum == newPhoneNum) {
printf("The addition of the contact has failed, \
since the phone number %s already exists!", newPhoneNum);
//free
return 0;
}
current = current->next;
} while (current != NULL);
//assigning
phonebook[letter]->firstName = newFirstName;
phonebook[letter]->lastName = newLastName;
phonebook[letter]->phoneNum = newPhoneNum;
return 0;
}
in addition, i havent figured out the linked list part at all, i managed before to enter the details to the structure (though im not sure if i even pointed the struct to the right place) but i dont know how to iterate after the first addition of the name. if i intialize current->next to be NULL for the first time, it will also happen the next time i call the function.
currently the code stops due do access violation but it seemed that after the first name i had error with reading the inputs that only occured after the second time.
You are actually pretty close to making it work. Probably the main problem with this code is that it has only pointers to the data, doesn't have space to store the data. You are pointing to phonebook[letter]->lastName = newLastName, a local variable that is destroyed when the function returns. This will make your strings a dangling pointer; when you try to access this data, undefined things happen. Probably the easiest way to fix that is to make a char array of maximum length instead of the pointers. You don't need to typedef in most cases, and sometimes it's confusing. I would recommend that you take the typedef out and just have,
#define SIZE 128
struct Contact {
char firstName[SIZE];
char lastName[SIZE];
char phoneNum[SIZE];
struct Contact* next;
};
Double-pointer Contact** phonebook is valid, but a recipe for confusion. Instead of naked pointers, use struct to encapsulate a phone book, using a list of struct Contact.
struct Phonebook {
struct Contact *letter[26];
};
printf is defined in stdio.h. strcmp is defined in string.h. malloc and exit are stdlib.h.
See What's the correct declaration of main()? C doesn't scan ahead; switch the order of the functions or have a prototype above.
Perhaps in the future you will read from a file? It's easier do if you read the input separately from the interface. Maybe split it up into a separate function. This should be static, since it doesn't need to be published to other translation units.
static struct Contact *inputContact(void)
To allocate memory, current = malloc(sizeof *current);. Did you have a typo using phonebook? If you allocate it first, you can read directly into the allocated memory and not do any copying. Make sure you limit the size. (scanf is not meant for this.)
#define STR(n) STR2(n)
#define STR2(n) #n
if(scanf("%" STR(SIZE) "s%" STR(SIZE) "s%" STR(SIZE) "s",
current->firstName, current->lastName, current->phoneNum) != 3)
exit(EXIT_FAILURE);
Then,
static int addNewContact(struct Phonebook* phonebook, struct Contact *contact)
do-while checks that the current is valid after you use it; you want while.
//get number of the letter in the alphabet
int letter = contact->lastName[0] - 'A'; // might want to check that
struct Contact *current = phonebook->letter[letter];
//check if details are being used
while (current != NULL) {
In C, equality means they are the same memory location, not in general the same text. You probably want a library function strcmp. (But are you sure your logic is correct in that it prevents the same number in appearing with the same first letter of the last name?)
if (!strcmp(current->phoneNum, contact->phoneNum))
Assigning will just overwrite the one letter that is there. You probably meant for it to be appended to the list.
contact->next = phonebook->letter[letter];
phonebook->letter[letter] = contact;
return 1;
And lastly, be sure to initialize any data that is of automatic duration.
struct Phonebook phonebook = {0}; /* Initialize null lists. */
addNewContact(&phonebook, inputContact());
--edit
This can be seen as creating a static-26-bucket separately-chained hash-table, with your hash function being hash(struct Contact *entry) { return entry->lastName[0] - 'A'; }.
I think you are doing this, which also makes sense. Make sure that you allocate Contact and 3 text fields, for a total of 4 mallocs per entry. If you read the data into a temporary buffer, you can use strcpy to transfer it to a longer-lived string that you've just allocated.

C LinkedList storing the last value only

I am having problem storing all the values into the Generic LinkedList, my linkedlist works totally works on a normal user Keyboard input but when I try to store values(strings) from a file, there is something weird happening, it only store the last value of the file.
I have checked my addToList() function but theres nothing wrong with it.
P.s But I am feeling its either I am printing wrong or my reading from the file into the linkedlist is wrong.
Thank you.
#include<stdio.h>
#include <stdlib.h>
#include<string.h>
#include "LinkedListItems.h"
#define MAX 10000
int main()
{
printf("Testing MissileFIle.txt");
void* secondStr;
//Had to malloc the thing
secondStr = (void*)malloc(1*sizeof(char));
FILE* missileFile;
missileFile = fopen("missiles.txt", "r");
if(missileFile == NULL)
{
printf("The file is empty");
}
number_list_t* missileList = calloc(1, sizeof(number_list_t));
void* input;
//Have to allocate the input
input = malloc(1*sizeof(void*));
//this is to read the data into the second Str
while(fgets(secondStr,MAX,missileFile) != NULL)
{
//Let just print out first just to test my memory
printf("%s\n",secondStr);
//Right now its only reading one string so far which is really weird AFFFFF
addTolist(missileList,secondStr);
}
//Gotta declare another list just to print out the list
number_node_t* current = missileList->head;
while(current != NULL)
{
//There is something wrong with this line
printf("%s\n",current-> number);
current = current-> next;
}
fclose(missileFile);
}
OUTPUT:
Testing MissileFile.txt
splash
single
V-line
h-line
Single
Single
Single
Single
Single
Single
typedef struct NumberNode
{
//It can store any data type
void* number;
struct NumberNode* next;
}number_node_t;
//List of Nodes
typedef struct NumberList
{
number_node_t* head;
int count; //This is not nesssary but it can be useful for counting how many variables
}number_list_t;
void addTolist(number_list_t* list, void* newNumber)
{
//tem[ = newNode]
number_node_t* newNode = calloc(1,sizeof(number_node_t));
newNode->number = newNumber;
newNode->next = list->head;
list->head = newNode;
}
INPUT DATA:
single
splash
single
V-Line
h-line
Single
The way you have implemented this, it cannot work.
The main problem, among many, is related to the void* pointers which cannot be dereferenced.
The size of elements should be given, either on creating the list in which case all elements are of the same type, or separately for each individual element. You can check out this question for an example of something that could work.
As far as the buffer thing is concerned, addToList should allocate new memory for each newNumber. What you are currently doing results in all data of the list pointing to a specific space in memory (the one allocated to secondStr). Each time you change the content of that memory space, all elements in the list are affected. This is why you print the same value for all elements and more specifically the last value in your file.
The way you allocate memory is also not really ok, same goes for the way you open your file, there is memory leaking etc. I am not going into details.
At least this issue:
Copy the string
OP's goal includes the need to copy the string from the read buffer to the list, not just copy the buffer pointer.
// void addTolist(number_list_t* list, void* newNumber) {
void addStringTolist(number_list_t* list, const char *s) {
// number_node_t* newNode = calloc(1,sizeof(number_node_t));
number_node_t* newNode = calloc(1, sizeof *newNode); // todo: add error check
size_t sz = strlen(s) + 1;
newNode->number = malloc(sz); // todo: add error check
strpy(newNode->number, s);
newNode->next = list->head;
list->head = newNode;
}
Note: When freeing the list, newNode->number also needs to be free'd.
regarding:
while(fgets(secondStr,MAX,missileFile) != NULL)
MAX is defined as 10000 but secondStr is defined as pointer to one byte. so when this is executed, a buffer overflow occurs.
This is undefined behavior and probably the root of the problem with reading from a file

C char array getting corrupted after being passed into function

I'm trying to implement a program similar to 20 Questions, in which a text file of the questions and guesses for answers are loaded, copied into a char array (where the new space lines are replaced by '/0' in order to split the questions into individual strings). The array works fine after the text file is copied into it. A tree structure is set up to organize the phrases into the yes/no question tree, where the left child is the yes response, while the right is the no response, and leaves are the guesses that the program uses to guess at the end.
The issue that I'm having is that after I build the tree (call treeBuilder from InitTree), the contents of the array where the phrases from the text file were copied became corrupted.
Before I call InitTree, the array contents look like this:
Is it furry? Does it meow? a cat a dog Does it have tusks? Does it have big ears? an elephant a rhinoceros an alligator
After calling it, it looks like this:
Is it furry? -???` ?p ?a dog Does it have tusks? Does it have big ears? an elephant a rhinoceros an alligator
I've been testing where it stops working, and within treeBuilder, all of the elements of the array are intact, but as soon as the function call to treeBuilder ends, the array becomes corrupted. I've tried protecting the memory by using calloc whenever I allocate memory, and even by making the character array static, which worked in a similar situation where this happened. But all of my preventative measures don't seem to be working and I'm not sure where the problem lies. I've already tried looking at similar cases here on stackoverflow but I couldn't anything that related to my issue.
This eventually leads to a seg fault, when the program actually starts to use the tree, for obvious reasons.
I've tried running gdb, but for whatever reason it won't let me go through line by line, because it cannot find the line information, and just skips everything until it either prompts for input, or gets a memory error or something, so running gdb isn't very helpful here. I'm guessing this might be because the main function is in an included file or something. But that's beside the point.
Here's the code related to the problem:
struct treeStruct {
char *string;
struct treeStruct *left, *right;
};
typedef struct treeStruct *TreeType;
// Builds a tree
void treeBuilder(TreeType tree, char **phrase, long level){
// Gets the level (number of tabs) of the next phrase
long nextLevel = countTabs(*phrase + strlen(*phrase) + 1);
tree->string = *phrase + level; // Assigns the response pointer to the tree array
// Move the pointer to the next string, since the the strings need to be
// put into the tree in linear order
(*phrase) += strlen(*phrase) + 1;
if (level >= nextLevel){
// Compares the current level with the level of the next string
// to determine if returning up the tree is necessary;
// This should be the answer to a question.
tree->left = NULL;
tree->right = NULL;
return;
}
else{
// Makes sure the left and right pointers of the struct have
// allocated space
tree->left = calloc(1, sizeof(TreeType));
tree->right = calloc(1, sizeof(TreeType));
// Adds the yes and no branches to the tree, recursion will take care
// of adding sub-branches
treeBuilder(tree->left, phrase, level + 1);
treeBuilder(tree->right, phrase, level + 1);
}
return;
}
TreeType InitTree (char *file){
if(file == NULL){
printf("File '%s' does not exist.\n", file);
exit(2);
}
FILE *fp;
fp = fopen(file, "r");
// Create a space in memory for the loaded questions to occupy
static char *phrases;
phrases = (char *)malloc(MAXSTR * MAXNUMQS * sizeof(char));
copyText(fp, phrases);
fclose(fp);
// Create space in memory for the tree structure
TreeType tree;
tree = (TreeType) calloc(1, sizeof(TreeType));
// Create a pointer to a pointer so that treeBuilder can
// change what the first pointer is pointing to, so the strings in
// phrases can be added in order throughout the recursion
static char *phrase_ptr, **phrase_ptr2;
phrase_ptr = &phrases[0];
phrase_ptr2 = &phrase_ptr;
//Build the tree
treeBuilder(tree, phrase_ptr2, 0);
topNode = tree;
return tree;
}
Sorry if this is tl;dr, but I wanted to be as clear as possible on my issue.
Just one thing I noticed is that you're using sizeof(TreeType), but TreeType is a pointer to a struct and not the struct itself. This means that you are creating a pointer that is pointing to nowhere, and that dereferencing the pointer will lead to undefined behaviour. Which having just read the rest of the question would certainly explain the segfaults.
I think you would be better off not typedef-ing your struct as a pointer, and be more explicit with your use of pointers.
eg.
typedef struct treeStruct TreeType;
void treeBuilder(TreeType *tree, char **phrase, long level){
...
if (!tree->left) {
// calloc returns a pointer to a new bit of memory that has been
// assigned on the heap
TreeType *temp = calloc(1, sizeof(TreeType));
// assignments below not explicitly needed as you're using calloc
temp->string = NULL;
temp->left = NULL;
temp->right = NULL;
tree->left = temp;
}
...
}
Here's a question about typedef-ing pointers. Seems to be relatively common in C, and used to imply that the data type is opaque and should not be dereferenced by the user (only by the API calls that the user passes it to).

Linked List in C (apparently malloc doesn't want to be my friend)

I was so pleased with myself getting this to work last night without any errors or warnings on my first try too! But, of course, I changed a bunch of stuffed and screwed it up...
When I tried to gdb it, the list from this.ytxt seemed load to memory just fine. I think the problem was writing it. Now. it works again but only writes the first line of the file. I commented out whole functions and printf'd test marks and still couldn't figure it out.
the idea is to read a variable number of lines from a file and print them in pairs. (Actually
it was meant to be like study flashcards but I never got around to that part)
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
struct member{ //This emulates a dictionary
char key[20]; //and links each word+definition pair to the next pair.
char def[20];
struct member *ptr;
};
struct member *root;
struct member *curr;
FILE *f;
int fill_list(){ //Fill each member struct with next two lines of
curr=root;
char this[20]; //FILE *f
while(EOF){
if(!fgets(this,20,f)) break;
strcpy(curr->key,this);
if(!fgets(this,20,f)) break;
strcpy(curr->def,this);
curr=curr->ptr;
curr=malloc(sizeof(struct member));
curr->ptr=0;
}
return 0;
}
void free_all(){
curr=NULL;
while(curr!=root){
curr=root;
while(curr->ptr)curr=curr->ptr;
free(curr);
}
}
int terminate(int i){ //The terminate function closes file and
free_all(); //frees malloc'd memory, then returns main func's
fclose(f); //return value.
return i;
}
int main(){
f=fopen("this.txt","r");
if(!f)return -1;
root=malloc(sizeof(struct member));
root->ptr=NULL;
fill_list();
curr=root;
if ( curr != 0 ) {
while ( curr != 0 ) {
printf( "%s", curr->key );
curr = curr->ptr;
}
}
free_all();
return terminate(0);
}
Elaborating on Chad's answer, you could have:
int fill_list(){ //Fill each member struct with next two lines of
struct member *new_mem;
curr=root;
char this[20]; //FILE *f
while(1){ /* relying on the breaks below to exit the loop */
if(!fgets(this,20,f)) break;
strcpy(curr->key,this);
if(!fgets(this,20,f)) break;
strcpy(curr->def,this);
/* create the new member */
new_mem=malloc(sizeof(struct member));
/* set the new member's next ptr to NULL */
new_mem->ptr = NULL;
/* set the current member's next to the new member */
curr->ptr=new_mem;
/* current is now the new member */
curr = new_mem;
}
return 0;
}
EDIT: thought I'd just add that if I was going to make slight modifications to your code this is what I'd do. If I were to do it from scratch I wouldn't structure the loop that way or have unnecessary global variables like curr. Same goes for the point made by sarnold where you only have a single temporary buffer. Not to mention that your last entry in the list could be invalid; it might be a better idea to allocate the next member entry in the list only after you successfully read the two strings into two temporary buffers.
Some possible bugs:
Do not have variables named "this". "this" is C++ reserved word. (Probably ok if you are compiling as C)
Your free_all() function looks suspicious. It took me a few glances to figure out what was going on. It looks like you are trying to free the linked list by traversing to the tail, deallocating the last node, and starting back from the top of the root again. This will have n-squared performance compared to freeing in a linear fashion. I think you want to say this:
void free_all()
{
struct member* curr = root;
while (curr)
{
struct member* next = curr->ptr;
free(curr);
curr = next;
}
}
int fill_list(){ //Fill each member struct with next two lines of
curr=root;
char this[20]; //FILE *f
while(EOF){
/* ... */
Your while(EOF) loop will never terminate here -- EOF is defined in stdio.h to (-1):
/* End of file character.
Some things throughout the library rely on this being -1. */
#ifndef EOF
# define EOF (-1)
#endif
It would be unwise to redefine EOF in your own program.
If you really want an infinite loop, please use one of while(1) or for(;;); Both of these are very obviously infinite loops, and both of these are common C idioms for infinite loops. Better would be re-writing your loop's exit condition into the while(), but sometimes that is difficult. (do { /* foo */ } while () is sometimes the perfect solution, and is probably better here.)
I'm not sure what exactly you should do to fix your while() loop condition, because I'm not entirely sure what it is supposed to be doing:
while(EOF){
if(!fgets(this,20,f)) break;
strcpy(curr->key,this);
if(!fgets(this,20,f)) break;
strcpy(curr->def,this);
You might as well be reading directly into curr->key and curr->def. (Reading into temporary storage makes sense if you want to keep your objects consistent even in the face of errors, but you'd need two temporary variables for that, and update the values after both IO commands. Up to you.)
curr=curr->ptr;
curr=malloc(sizeof(struct member));
curr->ptr=0;
}
In this small piece, you over-write the curr pointer with the value of the next node. Then you allocate a new node and over-write the curr pointer again. Then you null out the curr->ptr pointer in the newly allocated object. The curr object now has uninitialized curr->key and curr->def character arrays. Is this intentional? (Allowing half-initialized objects to live in your program is usually a recipe for disaster.)
In fill_list() you incorrectly allocating objects.
curr=root;
// now curr is a copy of root->ptr
curr=curr->ptr;
// curr allocated properly, but not attached to root at all!
curr = malloc(...)

List and Strings issues in C

I made a list to do some data treatment and I'm having an issue that I don't find the cause, for me my code seems right but there are issues.
What I'm trying to do is the following :
I have a list that contains x elements. I want to add an element p in the list then take every x element, add p to the string they represent, and add them to the list. (the list by itself works great it's just that operation that causes troubles).
The problem is that when I do that and when I try to display the list the first x+p elements are displayed well, but after I see some strange characters that have nothing to do with the inputs.
Here are the functions I use :
void addFirst(struct list *l, char *key)
{
struct node *x = createNode(key) ;
if (l->size == 0)
{
l->first = x;
}
else
{
x->next = l->first;
l->first = x;
}
l->size++;
return;
}
void showList(struct list* l)
{
struct node *p=l->first;
while (p!=NULL)
{
printf("%s \n",p->key);
p=p->next;
}
return;
}
void copyPlus(struct list* l,char *ch)
{
struct node *p=l->first;
addFirst(l,ch);
while (p!=NULL)
{
int len1=strlen(p->key);
char cat[len1+2];
strcpy(cat,p->key);
strcat(cat,ch);
cat[len1+1] = '\0';
printf("[%s] \n",cat);
addFirst(l,cat);
printf("{%s} \n",l->first->key);
p=p->next;
}
return;
}
int main()
{
struct list *A=createList();
addFirst(A,"1");
addFirst(A,"2");
addFirst(A,"4");
copyPlus(A,"3");
printf("=%s= \n",A->first->key); //this one works!
printf("=%s= \n",A->first->next->key);
printf("=%s= \n",A->first->next->next->key);
showList(A);
deleteList(A);
}
I skipped the irrelevant stuffs, it's a classic list.
Node is defined that way :
struct node
{
struct node *next;
char *key;
};
After further ivestigation it appears that the process is working correctly (the two //printf in copyPlus work the way they should). And the last //printf doesn't display anything, even if I do A->first->next->next->next.
It shows 3 if I do A->first->next->next->next->next.
I really don't understand and it's starting to get on my nerves, the code is simple and short and I'm still not seeing the mistake.
Could someone help me? Thanks.
Ok, so strcat adds a terminating zero to the string, you need space for one more char. strlen will give you 1, you will allocate a char array with size 2. That's not enough - you need at least 3 for the first char, second char and terminating zero. That's still dangerous, as you don't know the length of the second string. The best solution is thus char* cat = malloc(len1 + len2 + 1).
The current problem is that char cat[len1+2]; is allocating space on the stack (that's where local function variables reside). You're basically keeping a pointer to an address inside of a stack frame, which gets destroyed after the function has finished. The first value works, because this was your last function call and still noone has decided to overwrite this memory (but anyone is free to do so). Allocating with malloc() will allocate on the heap and the value will be available until you explicitly call free.
After modifications output is:
[43]
{43}
[23]
{23}
[13]
{13}
=13=
=23=
=43=
13 23 43 3 4 2 1
A C++ solution can be found at http://pastebin.com/xNzyLQ2N .

Resources