Compare using strcmp on linked-list - c

I'm not a great understanding on linked-list, i don't know if it's possible, but i need to do it :) I have a linked list that are load to the struct, and i need to compare a all the chars on the struct....It's better with an example:
This is without linked lists
struct
typedef struct x{
char name[100];
}x;
typedef x Info;
typdef struct Elem{
Info node;
struct Elem*next;
}Element;
for(i=0;i<100;i++){
if(strcmp(a.name[i],a.name[i+1])==0){
printf("Same name\n");
}
}
else
printf("Diff name\n");
Now i need to do something like this but with linked-list

First of all: int strcmp ( const char * str1, const char * str2 ) compares two C-strings (char pointers). This means that a.name[i] should be a char pointer and not a char! Make sure this is the case (i.e. make sure a.name is an array of c-string arrays, and not an array of chars).
Secondly, if the previous is the case, your code will only compare string i with string i+1. It will not compare all strings with each other.
In any case, it looks like you are not doing whatever it is you want to do the right way. I'm guessing you want a struct that is defined like this:
struct example {
char * name;
// other members of choice
example * next;
}
A placeholder for a name, other members, and a next pointer to enable the linked list data type. That way you can compare names with:
while (list->next != 0 && list->next->next != 0) {
if (strcmp(list->name, list->next->name) == 0) // do something;
else // do something else;
}
or with a double loop if you want to compare all strings with each other.

So the first thing you need to do is understand the fundamentals of linked-list. You can read in detail here: http://www.codeproject.com/KB/cpp/linked_list.aspx
NOTE: You really can't undersand linked lists until you understand pointers. http://www.cplusplus.com/doc/tutorial/pointers/
Essentially a linked-list is composed of numerous "nodes" that link to each other. At a minimum each node will have two pieces of data, one being the data (in your case a character) and the other being a pointer to the next node in the list.
Defining a struct would look like (in pseudocode):
LinkedList nodeT {
char *c; //NOTE: strcmp only compares pointers to chars
nodeT *nextNode;
}
You would have a pointer to the first node of the linked list. Something like:
nodeT *firstElement;
Then cycling through the entire list is a piece of cake:
nodeT *curElement = firstElement;
while(curElement->next != NULL) { //assuming the last node's next pointer is NULL
if(strcmp(curElement->c,curElement->next->c)==0){
printf("Same name\n");
} else {
printf("Diff name\n");
}
curElement = curElement->nextNode;
}
But again, to understand this you need to understand the fundamentals of pointers.

Here is a program that traverses the linked list and compares the names of adjacent elements. I have taken the liberty of renaming a couple of things, but otherwise the code for the data structures is the same as yours.
#include <string.h>
#include <stdio.h>
#include <assert.h>
typedef struct Info_ {
char name[100];
} Info;
typedef struct Element_ {
Info info;
struct Element_* next;
} Element;
void print_comparisons(Element* elm)
{
assert(elm);
Element* cur = elm;
Element* next = cur->next;
for (; next; cur = next, next = next->next) {
if (strcmp(cur->info.name, next->info.name) == 0)
printf("Same name\n");
else
printf("Diff name\n");
}
}
int main()
{
Info a; a.name[0] = 'A'; a.name[1] = '\0';
Info b; b.name[0] = 'B'; b.name[1] = '\0';
Info c; c.name[0] = 'B'; c.name[1] = '\0';
Info d; d.name[0] = 'D'; d.name[1] = '\0';
Element na; na.info = a;
Element nb; nb.info = b;
Element nc; nc.info = c;
Element nd; nd.info = d;
na.next = &nb;
nb.next = &nc;
nc.next = &nd;
nd.next = NULL;
print_comparisons(&na);
}
The output of the program:
Diff name
Same name
Diff name

Related

Able to access struct member through character in c?

Basically I have a struct with several members, named a-z. I have a string where I want each letter to correspond to the correct struct member. Currently I use a switch statement with each case in order to access the correct letter member of the struct, but Im wondering if theres a better (cleaner/shorter code) way to do this, without having to put 26 case statements with nearly identical code inside? My code looks somewhat like this:
typedef struct node
{
struct node *a;
struct node *b;
struct node *c;
...
struct node *z;
}node;
node *nTable[26][26][27];
int main
{
...
node *nWord = malloc(sizeof(node));
node *nPath = nWord;
nTable[0][0][0] = nWord;
char *cWord
cWord = "abcde";
for (int n = 0; n < 5; n++)
{
nWord = malloc(sizeof(node));
switch (cWord[n])
case 'a':
nPath->a = nWord;
nPath = nWord;
break;
case 'b':
nPath->b = nWord;
nPath = nWord;
...
case 'z':
nPath->z = nWord; //code is the same for each case, only difference between each is which member its assigned to
nPath = nWord;
}
}
Note the above code is a much reduced form of my actual code, so there may be some basic syntax and other errors within this example, but the general purpose of my code should be apparent.
So is there a cleaner way to do this, without using a case statement for each letter? Something simple like "nPath->cWord[n] = code;" would be perfect! (though this as it is, obviously does not work)
Any ideas would be great! Also sorry in advance if Ive left out any important info
For starters this construction
char *cWord = {a,b,c,d,e};
is syntactically invalid. You may not initialize a scalar object with a braced list with more than one initializer.
As for you question when you could declare one data member of an array type within the structure instead of numerous data members like
struct node *a;
For example
#define N 26
typedef struct node
{
struct node *nodes[N];
} node;
And then use the following approach
const char *letters = "ABCDEFGHIJKLMNOPQRSTUVWXYZ";
char *p = strchr( letters, toupper( ( unsigned char )cWord[i] ) );
if ( p != NULL )
{
nPath->nodes[p - letters] = data;
// or
// nPath->nodes[p - letters] = malloc( sizeof( node ) );
}
Maybe you can focus on the words: at first you have a linked list of words. And then there will be a linked list for every letter in order do build an array of linked lists of words.
Consider this example:
#include <stdio.h>
typedef struct _node
{
char* word;
struct _node* next;
struct _node* prev;
}; // single node contains one word
typedef struct _node Node;
typedef struct
{
char letter;
unsigned size;
unsigned limit;
Node* start;
Node* end;
} _list;
typedef _list Data;
In this way you have a bit more of structure
See this code
#include "x25list.h"
int main(int argc, char** argv)
{
Data* db[26];
for (int i = 'a'; i < 'z'; i += 1)
{ // builds initial linked lists
int ix = i - 'a';
db[ix] = (Data*)malloc(sizeof(Data));
db[ix]->letter = i;
db[ix]->size = 0;
db[ix]->end = NULL;
db[ix]->start = NULL;
}; // for()
return 0;
};
In this way you have a linked list for each letter already built and start to catalog words using the notes on the lists pointed by the value of the letter minus the value of 'a'.

Sort in alphabetical order a List in c

Hi i am writing a program that manage a list of student, i am using a list, each element is described like this:
struct student
{
char lastname[50];
char name[50];
char date_of_birth[50];
char height[50];
struct student *next;
};
struct student *root=0; //this is the root node
This is how i add element to the list:
void add_element(struct student **root, char lastname[50], char name[50], char date_of_birth[50], char height[50])
{
if(*root == 0)
{
*root = malloc(sizeof(struct student));
strcpy((*root)->lastname,lastname);
strcpy( (*root)->name,name);
strcpy( (*root)->date_of_birth,date_of_birth);
strcpy( (*root)->height,height);
(*root)->next = 0;
}
else
{
add_element(&(*root)->next,lastname,name,date_of_birth,height);
}
}
I also wrote 2 function, one is for reading from a file, the other is to write the file, the file contains all the students, everything works but i need a function to sort all the element in alphabetical order by lastname, i tried to write one, but it doesn't work, it keeps crashing.
I tried a lot of things and they didn't work, this is one attempt, and it doesn't work :-(
please help me
void sort(struct student *head)
{
struct student **current;
struct student *tmp;
for(current = &head ; *current !=NULL ; current = (*current)->next)
{
if((*current)->next == NULL)
{
break;
}
switch(strcmp((*current)->lastname,(*current)->next->lastname))
{
case 0:
{
printf("user not valid");
break;
}
case 1:
{
tmp = *current;
*current = (*current)->next;
(*current)->next = tmp;
break;
}
}
}
}
After including remarks from comments to correct the proposed source code, the algorithm to sort the linked-list is missing some steps. At least, to sort a linked-list, it is necessary to have two loops. The choice used of a struct student **current access will be complex for a two nested loops.
Here is another powerful sorting function using the optimized qsort() function.
Step 1 - before showing the function, to sort a list, the root pointer shall be modified.
First method, used for the add_element() by sending the address of
the pointer.
void sort(struct student **root)
{
...
}
Second method, to return the modified root.
struct student *sort(struct student *root)
{
...
return (root);
}
Step 2 - the function sort() using qsort() quicksort function.
The method allocates a temporary array of pointers in order to have a fixed-size element to be sorted.
The first loop is necessary to know the number of pointers to be sorted (if lower than 2, no sort is needed);
After allocating the array of struct student *, fill the array by using a loop to each item of the linked-list;
Call the qsort() function by using the customized comparison function node_compare() (see next step);
Restore the linked-list with the sorted pointers by forcing the value of the struct student *next (the first is *root and the last is pointing to NULL).
free the temporary array of struct student *;
That's all.
//
void sort(struct student **root)
{
struct student *tmp;
struct student **array;
int i,icount;
// number of nodes to be sorted
for(tmp = *root,icount = 0;tmp!=NULL;tmp = tmp->next,icount++);
if (icount<2) {
// no sort needed
return;
}
// allocate an array of pointers
array = (struct student **)malloc(icount*sizeof(struct student *));
// push linked-list into array of pointers
for(tmp = *root,icount = 0;tmp!=NULL;tmp = tmp->next,icount++) {
array[icount]=tmp;
}
// quicksort using node_compare() customized function
qsort(array, icount, sizeof(struct student *), node_compare);
// pop linked-list from array of pointers
*root = array[0];
(*root)->next = NULL;
for(tmp = *root,i = 1;i<icount;i++) {
tmp->next = array[i];
array[i]->next = NULL;
tmp = tmp->next;
}
// free the allocated array of pointer
free(array);
}
//
Step 3 - the comparison function node_compare() needed to qsort().
The function shall return a signed comparison as strcmp() does.
int node_compare(const void * a, const void * b)
{
// restore node pointers
struct student *node_a = *((struct student **)a);
struct student *node_b = *((struct student **)b);
if (node_b==NULL) return (-1); // force 'node_a'
if (node_a==NULL) return (+1); // force 'node_b'
// use the strcmp() function
return (strcmp(node_a->lastname,node_b->lastname));
}
Enhancement - because the add_element() is using a recursive call not compliant with a long linked-list, here is a quite simple non-recursive algorithm.
If the recursive algorithm limits the size to few-centuries of
elements, the proposed one has been tested with 100,000 elements (40Mb
linked-list), generated randomly and sorted.
void add_element(struct student **root, char lastname[50], char name[50], char date_of_birth[50], char height[50])
{
struct student **current;
for(current = root; *current !=NULL ; current = &((*current)->next));
*current = (struct student *)malloc(sizeof(struct student));
strcpy((*current)->lastname,lastname);
strcpy( (*current)->name,name);
strcpy( (*current)->date_of_birth,date_of_birth);
strcpy( (*current)->height,height);
(*current)->next = NULL;
}

deleting a student record from a single linked list

This is the code i have written to delete a particular student record in a linked list:
int delete ( struct student **q, struct student s,char *n ) {
if(*q==NULL)
{
printf("The linked list is empty\n");
return 0;
}
struct student *prev=*q;
while(prev->link!=NULL && prev->link!=n)
{
prev=prev->link;
}
if(prev->link==NULL)
{
printf("Student %s not found\n",n);
return 0;
}
prev->link=prev->link->link;
free(n);
return 1;
}
but i am getting a warning message telling comparison of distinct pointer types lacks a cast [enabled by default] for the while statement while(prev->link!=NULL && prev->link!=n)
This is the structure:
struct student
{
int id;
char name[10];
char gender[10];
struct student * link;
}*head;
and n stores the name of the student that has to be deleted.
There are many things not really working in your code.
I think you want to remove the whole struct matching the char* n from the linked list.
You cannot compare char*n and a struct, so this loop is incorrect:
while(prev->link!=NULL && prev->link!=n)
{
prev=prev->link;
}
You need to check if the first one doesn't match with your string, otherwise it would remain. If the first one matches, you need to reallocate the beginning of the struct, so you would use a **q in the declaration of the function (be sure to properly impact it). The first check would look like:
struct student *prev = *q;
if (strcmp(prev->name, n) == 0)
{
*q = (*q)->link;
prev->link = NULL; //not compulsory, but a good habit to take
free(prev);
}
I would write the loop this way :
while(prev->link != NULL && strcmp(prev->link->name, n) != 0))
{
prev = prev->link;
}
In C, you need to use strcmp() to compare two strings.
The no-match "if" would then remain identical.
Then, you have some issues with memory allocation. You cannot free fixed pointers (name[10] for instance), but only malloced memory.
So the end, after the no-match if, I advise a "else" that would look like:
else
{
struct student matched_student = prev->link;
prev->link = prev->link->link;
matched_student->link = NULL;
free(matched_student);
}
I think the type of prev->link is struct student *, but the type of n is char *, those type is different, so you can use
static_cast<char *>(prev->link) != n
or
(char *)(prev->link) != n
to fix the warning.

Linked list doesn't work as expected

I implemented this code to add an item to the list (it must be a string) and remove a specific string. However it has two problems: FIRST, the order is wrong after insert the nodes to the list. SECOND, after removing a node, it remains a "blank" space, see below when I remove the Third node.
Initial list:
First
Fourth
Third
Second
After list_remove():
First
Fourth
Second
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
struct myStruct {
char str[20];
struct myStruct * pNext;
};
struct myStruct *list_create(const char *str)
{
struct myStruct *node;
if(!(node=malloc(sizeof(struct myStruct))))
return NULL;
strcpy(node->str, str);
node->pNext = NULL;
return node;
}
int add_to(struct myStruct * list, const char *str)
{
struct myStruct *newnode;
newnode = list_create(str);
newnode->pNext = list->pNext;
list->pNext = newnode;
return 1;
}
char * remove_to(struct myStruct * list, const char *str)
{
while(list->pNext && (strcmp(list->str, str)))
list = list->pNext;
free(list);
return 0;
}
int list_foreach(struct myStruct *node, int(*func)(void*))
{
while(node) {
if(func(node->str)!=0) return -1;
node=node->pNext;
}
return 0;
}
int printstring(void *s)
{
printf("%s\n", (char *)s);
return 0;
}
int main(void)
{
struct myStruct *list;
// Create initial elements of list
list = list_create("First");
add_to(list, "Second");
add_to(list, "Third");
add_to(list, "Fourth");
printf("Initial list:\n");
list_foreach(list, printstring);
putchar('\n');
remove_to(list, "Third");
printf("After list_remove():\n");
list_foreach(list, printstring);
putchar('\n');
return 0;
}
I think I see a few problems:
add_to() always operates on the current list's first item. So every time you add, the new node will be inserted between the first and second (if there is a second).
And the method remove_to does not check if a matching string was actually found. After exhausting the while loop, if not match was found, I think you will free the last item.
C++ has a whole suite of "Collections" and a built in linked list is one of them. Unless this is a homework exercise where you have to implement your own, consider using that.

How do I sort a linked list of structures by one of the fields?

Wow now i know I dont. Lol.
I've got my structure like this:
struct Medico{
int Id_Doctor;
int Estado;
char Nombre[60]; ////focus on this part of the structure, this is name.
char Clave_Acceso[20];
char Especialidad[40];
struct Medico *next;
};
And I want to organize the structure depending on the name(alphabetical order..) any ideas on how to tackle this problem?
for example
Albert Haynesworth
Bob Marley
Carl Johnson
Thank you very much in advanced. :)(C, Unix)
Implementing a mergesort over a linked list in C is quite easy:
#include <string.h>
#include <stdlib.h>
#include <stdio.h>
struct node {
struct node *next;
char *data;
};
struct node *
divlist (struct node *n) {
int i = 0;
if (n) {
struct node *tail, *n2 = n;
while (1) {
n2 = n2->next;
if (!n2) break;
if (i++ & 1) n = n->next;
}
tail = n->next;
n->next = NULL;
return tail;
}
return NULL;
}
struct node *
mergelists(struct node *a, struct node *b) {
struct node *n;
struct node **last = &n;
if (!a) return b;
if (!b) return a;
while (1) {
if (strcmp(a->data, b->data) > 1) {
*last = b;
last = &b->next;
b = b->next;
if (!b) {
*last = a;
break;
}
}
else {
*last = a;
last = &a->next;
a = a->next;
if (!a) {
*last = b;
break;
}
}
}
return n;
}
struct node *
sortlist (struct node *n) {
struct node *tail = divlist(n);
if (!tail) return n;
return mergelists(sortlist(n), sortlist(tail));
}
int main(int argc, char *argv[]) {
int i;
struct node *n1, *n = NULL;
for (i = argc; --i >= 1;) {
n1 = (struct node *)malloc(sizeof(*n1));
n1->data = argv[i];
n1->next = n;
n = n1;
}
n1 = n = sortlist(n);
while (n1) {
printf("%s\n", n1->data);
n1 = n1->next;
}
return 0;
}
Note that you will have to modify this code to use your data structure and the right comparison!
C can't sort for you, nor maintain a sorted data structure. As others have suggested, you need to sort it yourself. I would do this when you create a new Medico, since inserting into a linked list is easy, and you can just find where it belongs as you iterate.
If Medico's order needs to be different, than you will need to sort the list whenever you display it. You'll probably want to iterate to pull out every name, then sort the resultant array using any of a number of techniques (depending on the size).
Assuming the list order is otherwise of no concern, keep it in order.
Sounds like you want to look at implementations of either quicksort or mergesort. I believe that the c std lib qsort implementation takes an array and not a linked list, so you may need to implement your own (although I'm pretty sure that you could find a readily available implementation on the interwebz if you did a quick search)
If you want to sort an array of structures, you can use the qsort function, see man qsort. It takes a base address of the array, number of elements, element size and comparing function:
int compare(const void *a, const void *b) {
Medico *medA = (Medico*) a;
Medico *medB = (Medico*) b;
return /* compare medA and medB */;
}
Medico *medicos = /* initialize */;
qsort(medicos, numberOfMedicos, sizeof(Medico), compare);
D’oh, just now I noticed the next-record pointer that probably makes this answer useless. (I’ve changed the question title to make the linked list apparent.) To make at least something from this answer, you can always copy the list into an array:
Medico *medicos = calloc(sizeof(Medico), numberOfMedicos);
Medico *current = /* first record in your linked list */;
int i = 0;
assert(current);
do {
medicos[i++] = *current;
current = current->next;
} while (current);
// Here you can sort the array.
free(medicos);
Of course, it depends on the number of records and other variables.
(My C is a bit rusty, feel free to fix.)

Resources