Help me, I am just a newbie.
I am currently studying and practicing linked list in C. I want to arrange the names of the instruments according to their sizes.
Problem is, every time I create a new instrument, the names of the previous instruments are overwritten by my newly created instrument but the sizes are not overwritten.
Why and What's happening there?
for example, the first instrument is "FLUTE" and size is 1, it will display those info. But when the 2nd loop comes and I input the second instrument ex., name is "TRUMPET" and size is 3, "FLUTE" gone..! It will display
name: TRUMPET, size: 1 //but the size is still there.
name: TRUMPET, size: 3
//here's my main
int main(void)
{
int add = 1;
int size;
char name[30];
instrument *start = NULL;
instrument *x = NULL;
instrument *y = NULL;
instrument *next = NULL;
while(add != 0)
{
printf("Enter the name of the instrument: ");
scanf(" %29s", name);
printf("Size: ");
scanf(" %d", &size);
next = pos(name, size);
if(start == NULL)
{
start = next;
}
if(x != NULL)
{
x->next = next;
}
x = next;
//for now, I'll just display the instruments instead of sorting them.
displayInstruments(start);
printf("\nDo you want to add more?: ");
scanf(" %d", &add);
}
freeInstruments(start);
return 0;
}
//this is my instrument creator function
instrument* pos(char *name, int size)
{
instrument *i = malloc(sizeof(instrument));
i->name = name;
i->size = size;
i->next = NULL;
return i;
}
//and other codes below here that don't matter for now. . . . . . . .
.
.
.
.
You create space for each instrument, but use the same space (the global variable name) for each of their names.
You are using a single buffer to store the name of each instrument. By default, ints will be copied so that you are correctly storing the size of each instrument. With strings, however, you store a pointer which holds the memory location of string. All of your instrument->name pointers are pointing to the same memory location, so they will all display the most recently added instrument name.
To fix this, change i->name = name to i->name = strdup(name), which will duplicate the string and create it's own personal copy.
Related
I'm trying to create a linked list inside a function by passing a pointer to the head of the list. Inside the function, everything works perfectly. But when I get back to main(), all of a sudden the pointer is NULL. So if I call the function again, it acts like I'm adding a node for the first time again.
What is the problem with my code?
struct course
{
int c_ID;
char *c_name;
struct course *c_next;
};
void new_course(struct course *c_head, struct course *c_tail); // adds a node
int main ( )
{
// variable declarations
int choice;
char y_n;
// create linked lists
struct course *c_head = NULL;
struct course *c_tail = NULL;
// print out menu, obtain choice, call appropriate function; loop if desired
do
{
printf("\t\t\t***MENU***\n"
" 1. Add a new course\n\n"
................................
"Enter the number of the menu option you wish to choose: ");
scanf("%d", &choice);
switch (choice)
{
case 1:
new_course(c_head, c_tail);
if (c_tail == NULL)
{
printf("We're screwed.\n"); // this excecutes every time
}
break;
.....................
}
printf("Would you like to return to the main menu? Enter y for yes, n for no: ");
scanf(" %c", &y_n);
} while (y_n != 'n' && y_n != 'N');
// free courses
struct course *c_temp = NULL;
c_temp = c_head;
while (c_temp != NULL)
{
c_head = c_head->c_next;
c_temp->c_ID = 0; // reinitialize the student ID
c_temp->c_name[0] = '\0'; // reinitialize the student name string
free(c_temp->c_name); // return the string memory to the system
free(c_temp); // return the node memory to the system
c_temp = c_head; // set temp to next item in the list
}
return 0;
}
void new_course(struct course *c_head, struct course *c_tail)
{
// declare variables
int ID;
char name[50];
// obtain user input
printf("Enter the course ID number and the course name, separated by a space: ");
scanf("%d%s", &ID, name);
if(c_head == NULL) // no courses yet
{
c_head = (struct course *) malloc(sizeof(struct course)); // allocate memory for c_head
c_head->c_next = NULL;
c_tail = c_head; // update c_tail
}
else // the list already has nodes
{
c_tail->c_next = (struct course *) malloc(sizeof(struct course)); // allocate memory for new node
c_tail = c_tail->c_next; // update c_tail
c_tail->c_next = NULL;
}
c_tail->c_ID = ID; // assign ID to c_ID component of new node
c_tail->c_name = (char *) malloc(sizeof(char) * strlen(name) + 1); // allocate memory for c_name component of new node
strcpy(c_tail->c_name, name); // assign name to c_name component of new node
printf("%d = %d, %s = %s\n", c_head->c_ID, ID, c_tail->c_name, name); // this always works, proving the list was created and the assignments worked
return;
}
In C, everything is passed by value, including pointers. The values of c_head and c_tail in the caller's context cannot be modified by new_course. To accomplish that, your function signature would need to look like:
void new_course(struct course **c_head, struct course **c_tail)
and throughout the body of new_course you would need to refer to *c_head and *c_tail, as in:
*c_head = (*c_head)->c_next;
and main would have to call it this way:
new_course(&c_head, &c_tail);
You need to pass pointers to pointers so you can change the value of c_head and c_tail.
Call like this
new_course(&c_head, &c_tail);
Use like this
void new_course(struct course **c_head, struct course **c_tail)
{
if((*c_head) == NULL) // no courses yet
{
(*c_head) = (struct course *) malloc(sizeof(struct course));
... etc. etc.
}
I'd not write it like this myself, but that's your problem.
C uses pass-by-value for function argument passing.
In your case, you're using the function
void new_course(struct course *c_head, struct course *c_tail)
and calling that with
new_course(c_head, c_tail);
No, from the function new_course(), you can change the value pointed to by c_head and c_tail, but you cannot change those two pointers themselves.
If you have to change c_head and c_tail from new_course(), you need to pass a pointer to them, i.e, a pointer to pointer.
Otherwise, you have another option to handle this case. If you want to simply pass the pointer and change the pointer itself from the function, you need to return the modified pointer from the function and collect that to the same variable which you had used as the argument (and changed inside the function). Then, the change will be reflected in the caller function.
That said, as a note,
Please see why not to cast the return value of malloc() and family in C.
sizeof(char) is guaranteed to be 1 in C. Multiplying by the same is redundant and can be avoided.
The recommended signature of main() is int main(void)
I have a hash table data structure where I keep a linked list of nodes with names and phone numbers. I've implemented an insert function that hashes the last name and inserts the node accordingly. Input was done manually via the console, and works completely as intended.
I am now in the process of implementing a function that will read this information from a file and call the insert function repeatedly (for each listing). Information in the file is formatted like this:
Test User 1234567890
Test User 1234567890
Test User 1234567890
It appears to work properly until I attempt to retrieve the values from my hash table, and I can only retrieve the last value added to the table (from the file, manual inputs work fine). I've followed each input all the way to the point where they are added to the linked list, and they still contain the correct values. I've also checked the hash function to make sure it is not placing them in the incorrect index, but the generated index is the same between the file and manual input.
Here is my file input code:
#define DEF_SIZE 50
char* lastName = malloc(DEF_SIZE * sizeof(char));
char* firstName = malloc(DEF_SIZE * sizeof(char));
char* phoneNumber = malloc(DEF_SIZE * sizeof(char));
printf("\nAttempting to load phonebook from file...\n\n");
f = fopen("phone.txt", "r");
if (f == NULL){
printf("Cannot open file.\n");
getchar();
exit(1);
}
int counter = 0;
while (fscanf(f, "%s %s %s", lastName, firstName, phoneNumber) != EOF){
insert(lastName, firstName, phoneNumber, hashTable);
counter++;
}
printf("Successfully inserted %d items from the file.");
And my insert function:
int insert(char *lastName, char *firstName, char *phoneNumber, node *hashTable[]){
//holder for linked list index
int hashResult;
//get key from last name
hashResult = hashFunction(lastName);
//create node for adding listing
node *addNode = malloc(sizeof *addNode);
//check if malloc is successful
if (addNode == NULL){
return 0;
}
//allocate space for names + number
addNode->lastName = malloc(strlen(lastName) + 1);
addNode->firstName = malloc(strlen(firstName) + 1);
addNode->phoneNumber = malloc(strlen(phoneNumber) + 1);
//add data to node
addNode->lastName = lastName;
addNode->firstName = firstName;
addNode->phoneNumber = phoneNumber;
//if empty linked list, create first item
if (hashTable[hashResult] == NULL){
start p = malloc(sizeof(node));
p->next = NULL;
}
//point new node's pointer to previous node
addNode->next = hashTable[hashResult];
//add node to hash table
hashTable[hashResult] = addNode;
//return successful
return 1;
}
If anyone knows anything regarding this issue, or how to approach looking for the cause I would greatly appreciate it, thanks.
I'm trying to create a linked list structure to store data. The head of the linked list seems to be updating somehow. I have the following code. I can't seem to figure out how put char array data into a node and keep it from updating when the address to said char array's data updates.
The following code prints out whatever string is passed into the processStr function. How do I keep head from updating ?
//Linked List Structure
mainNode *head = NULL;
//take and store word in data structure
void processStr(char *str){
//char array
char strArray[sizeof(str)+1];
//stores lower case string
char strLower[strlen(str)];
int i;
for(i = 0; str[i]; i++)
strLower[i] = tolower(str[i]);
strLower[i] = '\0';
//printf("%s : ", strLower);
//Starts Linked List
if(head == NULL){
mainNode *mainPtr = (mainNode *)malloc(sizeof(mainNode));
nameNode *namePtr = (nameNode *)malloc(sizeof(nameNode));
mainPtr->name = strLower;
mainPtr->numOccurances = 1;
mainPtr->next = NULL;
mainPtr->nextName = namePtr;
namePtr->name = strArray;
namePtr->next = NULL;
head = mainPtr;
}
printf("%s : " , head->name);
}
You assign the pointers mainPtr->name and namePtr->name to variables strLower and strArray that are declared locally in processStr(). That means after that function returns, any access to these pointers results in undefined behaviour. You could do sth. like
mainPtr->name = strdup( strLower );
instead to allocate memory for the strings.
Btw.: strLower must also be declared as char strLower[strlen(str)+1];
The above code will only run once only which will add information to head only once. If you want to add more information in case of second run then add code for else condition. Example:-
if ( head == NULL ) {
// code to insert data in case of first run
}else{
// code to insert data for second run and so.....
}
I have a problem writing a code that should read usernames and put them in list. Every username should be connected to the number of times it has been entered. The problem occurs when entering the second username, my code places that username in the variable called first (where the first is kept). I guess I've done something wrong with the pointers, but I cannot find what. I am confused, in the end of one while loop the first one is the real first one, and when the program enters while again, variable first changes. How could that be? Please help me.
Thank you :)
typedef struct _user
{
char *name;
int counter;
struct _user *next;
} user;
int main() {
char userName [10];
int found = 0, go_on = 1;
user *first = NULL, *temp, *new;
while (go_on == 1) {
printf ("Username: ");
scanf("%s", userName);
if (first) {
// printf ("The first one in list: %s\n", first->name); - this prints the name of last username entered
for (temp = first; temp; temp = temp->next) {
if (strcmp (temp->name, userName) == 0) {
temp->counter++;
found = 1; }
if (found== 1) break;}
if (!found) {
new = (user*) malloc (sizeof(user));
new->name = userName;
new->counter = 1;
temp = new;
temp->next = NULL; } }
else {
new = (user*) malloc (sizeof(user));
new->name = userName;
new->counter = 1;
first = new;
first->next = NULL; }
printf ("Go on? (1/0)");
scanf("%d", &go_on);
printf ("Current list: ");
for (temp=first; temp; temp = temp->next)
printf("%s %d\n", temp->name, temp->counter);
//printf ("The first one in list: %s\n", first->name); - this prints the correct first
}
}
Your error, I think, is the userName array. You should allocate a new one for each element in your linked list. When you write new->name = userName;, you are not copying the name to the struct, you are making the struct point to your userName[10] array. As such every struct's actual "name" is storing only the single last name scanf-ed. That being said...
I generally prefer to write that kind of code with dedicated tools instead of logically embedding them in a loop construct:
Keeping your struct:
typedef struct _user
{
char *name;
int counter;
struct _user *next;
} user;
I would create a function that, given a properly constructed Sll returns a matching element:
function user *user_match_name(user *user_head, const ch *name)
{
user *cur_user = NULL;
/* look for a match */
for (cur_user = user_head ; cur_user ; cur_user = cur_user->next)
if(!strcmp(name,cur_user->name) return cur_user;
/* no match */
return NULL;
}
Then I usually prefer to have an Sll element builder:
function user *create_user(const ch *name)
{
user *new_user;
if(!(new_user = malloc(sizeof(user))))
printf("Error in allocation"); /* or better malloc error handling */
/* IMPORTANT: PROVIDE MEMORY FOR THE NAMES!!! */
if(!(new_user->name = malloc(sizeof(char)*256))) /* sizeof(char) is useless but I like to explicit it like that. And 256 should be enough a buffer could be better made */
printf("Error in allocation"); /* or better malloc error handling */
strncpy(new_user->name, name,256); /* not sure if I got the argument order right... */
new_user->counter = 0; /* or 1 depending on your prefered convention */
new_user->next = NULL;
return new_user;
}
It ease the debugging like you wouldn't believe! Then it's just a matter of rewriting your main function:
int main() {
char userName [10];
int found = 0, go_on = 1;
user *user_head = NULL, *new_user,*temp;
while (go_on == 1) {
printf ("Username: ");
scanf("%s", userName);
if( (new_user = user_match_name(user_head,userName)) )
++new_user->counter
else
new_user = create_user(userName);
/* Here we push on the Sll */
if(user_head){
new_user->next = user_head;
user_head = new_user;
} else {
user_head = new_user;
}
printf ("Go on? (1/0)");
scanf("%d", &go_on);
printf ("Current list: ");
for (temp = user_head; temp; temp = temp->next)
printf("%s %d\n", temp->name, temp->counter);
//printf ("The first one in list: %s\n", first->name); - this prints the correct first
}
}
Ahhhhhh! Much easier to read. Be mindful of: 1) I didn't compile check the code. The important ideas are there, leverage them. 2) Even in your previous implementation, you are white space vulnerable but that's somewhat another topic.
Or you could cimply fix it by doing:
typedef struct _user
{
char name[10];
int counter;
struct _user *next;
} user;
and strncpy(new->name,userName,10) instead of assigning the pointer.
I have been busy with a question from a C book. The question is simple but it has some specific parts.
I would like to ask a question about arrays.
My question is about the best way with creating an array of a structure. The question wants these all;
Firstly create an array of structure. Secondly, create a linked list which connects these arrays with a restp pointer.
I want to divide my question into sub parts. First part is array of structure...
How can I create an array of a structure. I've made a research about this. And here is my way:
I'm creating a structure for my array of structure:
struct student{
int id;
struct courseList_node_s *restp;
};
And my linked list for completing rest of question:
typedef struct courseList_node_s{
char course[6];
int credit,
section;
struct courseList_node_s *restp;
}courseList_node_t;
I have implemented some function to handle this student schedule.
In my get_studentList function;
I declared my array as this;
struct student *ansp[size];
And making memory allocation;
ansp[i] = malloc(sizeof(struct student));
And lastly assigning a value;
ansp[i]->id =id;
Now, my problem is while creating an array, I couldn't make it as an ordered array. For instance, the user can type 1111, 1222, 1232, and then 1011. So, my first element of array which is ansp[0] = 1011, and ansp[1] = 1111.
I couldn't figure out.
Can you give me an algorithm which consist these(Creating an ordered array of structure).
Lastly, sorry for my bad English and I may made some grammatical mistakes...
Thanks in advance.
To order the elements, you will need to sort them. In C, you probably want to use qsort (in C++ there are easier ways). You will need to define a comparison function on struct student * and call qsort on your array with it.
See this example for inspiration. Note that your array is an array of structure pointers, the example is an array of direct structures (which is maybe what you wanted anyway?).
Can you give me an algorithm which consist these(Creating an ordered array of structure).
If you want to create an orderd array of structures, you probably want to build a tree.
There are libraries for that, but to learn and understand, you can Google 'Binary trees in C' or something like that, e.g.:
http://www.macs.hw.ac.uk/~rjp/Coursewww/Cwww/tree.html
Trees will allow your user to insert non-sorted values and retrieve them in sorted order (also, search them more quickly).
I'd solved the problem with helps #Keith Randall and
lserni
I have implemented both binary search tree and array of structure.
First way, sorting array with qsort:
I had to create a compare function:
int compare(const void *p1, const void *p2){
return (* (struct student **) p1)->id - (* (struct student **) p2)->id;
}
And my other helper functions;
void get_studentList(struct student **listp,int size){
int id,i;
struct student *ansp[size];
for(i=0;i<size;i++){
printf("Enter student's id to exit enter -1> ");
scanf("%d", &id);
ansp[i] = malloc(sizeof(courseList_node_t));
ansp[i]->id = id;
ansp[i]->restp = NULL;
}
qsort (ansp, size, sizeof(struct student *), compare);
for(i=0;i<size;i++){
listp[i] = ansp[i];
}
}
courseList_node_t * insert_studentSchedule(courseList_node_t *headp, int size){
courseList_node_t *cur_nodep;
if(headp == NULL){
cur_nodep = scan_course();
headp = cur_nodep;
} else {
headp->restp = insert_studentSchedule(headp->restp,size);
}
return (headp);
}
And my display function;
void display_schedule(struct student **headp, int size){
courseList_node_t *cur_nodep;
int i = 0;
while(i< size){
cur_nodep = headp[i]->restp;
printf("Student id > %d\n", headp[i]->id);
while(cur_nodep != NULL){
printf("Course name> %s\t", cur_nodep->course);
printf("Course credit> %d\t", cur_nodep->credit);
printf("Course section> %d\n", cur_nodep->section);
cur_nodep = cur_nodep->restp;
}
i++;
}
}
Second way, Binary Search Tree:
I changed typedef parts of my header file as this:
typedef struct tree_node_s{
int id;
struct courseList_node_s *restp;
struct tree_node_s *leftp, *rightp;
}tree_node_t;
And my macro to formalize a standart pattern in dynamic allocation of nodes:
#define TYPED_ALLOC(type) (type *)malloc(sizeof(type))
And my implementation of creating a binary search tree:
/*
* Insert a new id in a binary search tree.
* Pre: rootp points to the root node of a binary search tree
*/
tree_node_t * get_studentTree(tree_node_t *rootp, int newId)
{
if (rootp == NULL){
rootp = TYPED_ALLOC(tree_node_t);
rootp->id = newId;
rootp->restp = NULL;
rootp->leftp = NULL;
rootp->rightp = NULL;
} else if ( newId == rootp->id){
/* */
} else if (newId < rootp->id){
rootp->leftp = get_studentTree(rootp->leftp, newId);
} else {
rootp->rightp = get_studentTree(rootp->rightp, newId);
}
return (rootp);
}
This parts are not related with this question. I gave them because I want to share the partial solution of real question.
/*
* Its aim to add courses to restp component of subtree
* It may have some problems. And you can omit it. Because it not related with this question
* Pre: elementp not empty
*/
courseList_node_t * add_course(courseList_node_t *nextp, courseList_node_t *elementp){
if(nextp->restp == NULL){
nextp->restp = elementp;
} else {
nextp->restp = add_course(nextp->restp,elementp);
}
return (nextp);
}
/*
* It is not neccessary to first call get_studentTree function. It simply creates a linked list which consist of student class/lecture schedule.
* Pre: ele and id not empty
* Post: Tree returned includes all schedule and retains binary search tree properties.
*/
tree_node_t * insert_studentSchedule(tree_node_t *rootp,courseList_node_t *ele, int id){
if (rootp == NULL){
rootp = get_studentTree(rootp, id);
rootp->restp = TYPED_ALLOC(courseList_node_t);
strcpy(rootp->restp->course, ele->course);
rootp->restp->credit = ele->credit;
rootp->restp->section = ele->section;
}
else if(rootp->id == id){
if ( rootp->restp == NULL ){
rootp->restp = TYPED_ALLOC(courseList_node_t);
strcpy(rootp->restp->course, ele->course);
rootp->restp->credit = ele->credit;
rootp->restp->section = ele->section;
} else {
rootp->restp = add_course(rootp->restp, ele);
}
} else if ( id < rootp->id ){
if ( rootp->leftp != NULL )
rootp->leftp = insert_studentSchedule(rootp->leftp, ele, id);
} else if ( id > rootp->id ) {
if ( rootp->rightp != NULL )
rootp->rightp = insert_studentSchedule(rootp->rightp, ele, id);
}
return (rootp);
}
/*
* Course scanning function
*/
courseList_node_t * scan_course(void){
courseList_node_t *cur_coursep;
char courseName[6];
cur_coursep = (courseList_node_t *)malloc(sizeof(courseList_node_t));
printf("Welcome to course scanning part>\n");
printf("Enter the name of course> ");
scanf("%s", courseName);
strcpy(cur_coursep->course, courseName);
printf("Enter the credit of course> ");
scanf("%d", &cur_coursep->credit);
printf("Enter the section of course> ");
scanf("%d", &cur_coursep->section);
cur_coursep->restp = NULL;
return (cur_coursep);
}
/*
* My way to print binary search tree with all elements
*/
void display_schedule(tree_node_t *rootp){
courseList_node_t *cur_course;
if(rootp == NULL)
return;
display_schedule(rootp->leftp);
if (rootp->restp == NULL)
printf("Tree with id: %d element has no member!", rootp->id);
else {
cur_course = rootp->restp;
while (cur_course != NULL){
printf("Student Id> %d\n", rootp->id);
printf("Course name> %s\t", rootp->restp->course);
printf("Course credit> %d\t", rootp->restp->credit);
printf("Course section> %d\n", rootp->restp->section);
cur_course = cur_course->restp;
}
}
display_schedule(rootp->rightp);
}
It may not full solution of book question but with your helps, It is solution of essential parts. If you found a mistake. Feel free to add a comment.