Print linked list up to specific number in C - c

Suppose I have a linked list of unknown length. I would like to have a function to print out whole list if the length is less than 10, and if its length more than 10, then display only first 10 nodes.
However, because I'm comparing the pointer and integer to print out first 10 nodes, I'm getting the following error:
ordered comparison between pointer and integer ('NodeT *' (aka 'struct node *') and 'int')
for (current = list; current < 30; current = current->next)
If I change it to have a count and loop while count is less than 10, I'm getting a segmentation fault.
How can I display first 10 nodes if list is length is more than 10?
I have the following function:
void *printNodes(NodeT *list) {
int length = countNodes(list); // finds length of a linked list
int count = 0;
NodeT *current;
if (list == NULL) {
printf("Empty list.\n");
}
if (length < 10) {
// Display all if number of nodes is less than 10
for (current = list; current != NULL; current = current->next) {
printf("%s\n", current->data);
}
} else {
// Display first 10 if number of nodes more than 10
for (current = list; current < 10; current = current->next) {
printf("%s\n", current->data);
// for (current = list; count < 10; current = current->next) {
// printf("%s\n", current->data);
// count++;
}
}
return 0;
}

For starters the return type void * of the function printNodes
void *printNodes(NodeT *list) {
does not make a sense.
You should declare the function at least like
void printNodes( const NodeT *list) {
As the number of potentially outputted nodes is known there is no need to determine how many nodes there are in the list.
If the condition of this if statement
if (list == NULL) {
printf("Empty list.\n");
}
evaluates to the logical true the function shall return.
The condition of the for loop where a pointer is compared with an integer
for (current = list; current < 10; current = current->next) {
does not make a sense.
The function can be declared and defined the following way.
void printNodes( const NodeT *list )
{
size_t n = 10;
if ( list == NULL )
{
printf("Empty list.\n");
}
else
{
for ( ; list != NULL && n--; list = list->next )
{
printf( "%s\n", list->data );
}
}
}
Another approach is to declare one more parameter that will specify how many nodes of the list you want to output. For example
void printNodes( const NodeT *list, size_t n )
{
if ( list == NULL )
{
printf("Empty list.\n");
}
else
{
for ( ; list != NULL && n--; list = list->next )
{
printf( "%s\n", list->data );
}
}
}

Consider adapting your main for loop to serve as a counter:
void printNodes(NodeT *list) {
if (list == NULL) {
printf("Empty list.\n");
return; // Note no more useless "pointer" return
}
int limit = 10; // Could easily be an argument
NodeT *current = list;
for (int i = 0; current && i < limit; ++i, current = current->next) {
printf("%s\n", current->data);
}
}
The key here is you need to test that both the pointer is valid and the counter hasn't tripped.
In your adaptation you walked off the end of the chain without paying attention to your current pointer.

You can try the else part in this way:
for (current = list; count< 10; count++, current = current->next)
///your code

You can use a for loop as mentioned by tadman or a while loop like this
int counter = 0;
NodeT *current = list;
while (counter < 10 && current != NULL)
{
/* Do your stuff */
current = current->next;
counter += 1;
}
Instead of finding the length of the linked list as you did, which might make the time complexity of your function linear, you just need to check if the counter is at most ten and if the current node is not null.

Related

Getting user input for the deletion of the desired linked list element

NodePointer deleteNode(NodePointer head,int number)
{
NodePointer ptrNode;
NodePointer ptrNodePrev;
int count;
if(head == NULL)
{
printf("There is no element at list");
}
if(number == 1)
{
ptrNodePrev=head;
head=head->next;
free(ptrNodePrev);
}
else{
ptrNode=head;
while(ptrNode->next != NULL && count+1 != number){
count++;
ptrNodePrev=ptrNode;
ptrNode=ptrNode->next;
}
ptrNode=ptrNode->next;
printf("Node: %d-%d-%d - %s",ptrNodePrev->next->x.year,
ptrNodePrev->next->x.month,
ptrNodePrev->next->x.day,
ptrNodePrev->next->x.event);
printf("Successfully deleted");
free(ptrNodePrev->next);
ptrNodePrev->next=ptrNode;
}
return head;
}
Hi I've been learning single linked lists and wanted to do a example about it.Basically i ask user to input how many nodes does he want and then he fills them. After that i ask them to delete a node then they will enter a number which will supposedly deletes the according node.Its fine if the number inputed is not 1 but if it is then i would basically get random numbers. I dont get why it happens i looked through most of the questions about this topic here but couldnt find reason.Can anyone explain my mistake please ?
Actually when number is equal to 1 then the function works correctly.
NodePointer deleteNode(NodePointer head,int number)
{
NodePointer ptrNode;
NodePointer ptrNodePrev;
int count;
if(head == NULL)
{
printf("There is no element at list");
}
if(number == 1)
{
ptrNodePrev=head;
head=head->next;
free(ptrNodePrev);
}
else
{
//...
}
return head;
}
Maybe in main you forgot to assign the return value of the function to the pointer to the head node like
head = deleteNode( head, 1 );
Otherwise the function has undefined behavior because 1) the variable count is not initialized and 2) you do not check that after the while loop count + 1 is equal to number
while(ptrNode->next != NULL && count+1 != number){
count++;
ptrNodePrev=ptrNode;
ptrNode=ptrNode->next;
}
ptrNode=ptrNode->next;
//...
Pay attention to that in C indices start from 0. And the second parameter of the function should have an unsigned integer type as for example size_t. Otherwise the user is allowed to pass to the function a negative value.
Also the function should not issue any message.
The function can be declared and defined the following way.
int deleteNode( NodePointer *head, size_t n )
{
while ( n-- && *head != NULL ) head = &( *head )->next;
int success = *head != NULL;
if ( success )
{
NodePointer current = *head;
*head = ( *head )->next;
free( current );
}
return success;
}
And if in main you have a declaration of the pointer like
NodePointer head = NULL;
//...
then the function is called like
deleteNode( &head, n );
where n is some value specifying an index in the list starting form 0. That is if you want to delete the first node then you should write
deleteNode( &head, 0 );

Iterative method to Recursive method C Language

I have tried to convert this method that is already working in my program to recursive way. Because I was asked to do it. The thing is I have tried see below but in my method when try to add to he position the method value this value is a great number and create segmentation.
This is my method in iterative way:
int researchList_getPosByCountry(tResearchList* list, tCountry *country) {
// Check preconditions
assert(list != NULL);
tResearchListNode *prev = NULL;
int pos;
// check if is an empty list
if (researchList_empty(list)) {
pos = -1;
}
else{
pos = 1;
prev = list->first;
while ((prev != NULL) && !country_equal(prev->e->country, country) ) {
prev = prev->next;
pos++;
}
}
if (prev == NULL) {
pos = -1;
}
return pos;
}
This is my method in recursive way:
assert(list != NULL);
tResearchListNode *prev;
int pos;
// check if is an empty list
if (researchList_empty(list)) {
pos = -1;
}
else{
pos = 1;
prev = list->first;
if ((prev != NULL) && !country_equal(prev->e->country, country) ) {
prev = prev->next;
pos = pos + researchList_getPosByCountry(list, country); //Debugging the segmentation is here
}
}
You will get an endless recursion, since you call researchList_getPosByCountry always starting from the begin of the list; again and again and ...
I suggest you introduce a second (then recursively used) function that calls itself with the respective next node and returns (a) the "greatest" negative number possible if the node was not found (thereby turning any intermediate results on the call stack into a negative one), or return 0 to denote "country found, take the count so far", or "1 + next try" to continue counting. The recursive part could look as follows; you need then to call this one from your int researchList_getPosByCountry(tResearchList* list, tCountry *country) and interpret a negative result accordingly:
int researchList_getPosByCountry(tResearchListNode* node, tCountry *country) {
if (!node) {
return INT_MIN;
} else if (countryEqual(...)) {
return 0;
} else {
return 1 + researchList_getPosByCountry(node->next,country);
}
}

Check if Linked List is sorted (ascending order) or not in C?

struct node* acc_check(struct node *head) {
int count = 0, count2 = 0;
for (struct node *ptr = head; ptr->next != NULL; ptr = ptr->next) {
count++;
if (ptr->data <= ptr->next->data) {
count2++;
}
}
if (count == count2)
printf("Ascending Order");
else
printf("Not in Ascending Order");
return head;
}
I am always getting "Ascending Order", please help me to figure out the problem.
Here is the full source code, LINKED LIST CODE
If you look carefully to your code, you are sorting the elements of the list when creating the list:
case 1: {
head = create_11(head);
head = sort_list(head);
}
If you comment the sorting of the list you will obtain the expected result.
Independent on whether the list is already sorted or not in any case the function is incorrect.
For starters it can have undefined behavior because the user can call the function for an empty list. In this case this expression
ptr->next != NULL
will invoke undefined behavior.
The function shall not output any message. It is the caller of the function will decide whether to output any message. What it shall do is to return integer value either 0 or 1 reporting whether the list is unsorted or sorted.
Moreover to make the conclusion that the list is not sorted there is no need to traverse it to its end. The variables count and count2 do not make sense. They are redundant.
The function can be defined the following way.
int acc_check( const struct node *head )
{
if ( head != NULL )
{
const struct node *prev = head;
while ( ( head = head->next ) != NULL && !( head->data < prev->data ) )
{
prev = head;
}
}
return head == NULL;
}

How can I display the data I created in a linked list?

I think there is something wrong with my create.
void add(N *p) {
N *current, *start;
current = malloc(sizeof(p));
scanf("%d", &current->data);
current->next = NULL;
if (p == NULL) {
p = current;
start = current;
} else {
start->next = current;
start = current;
}
}
I think that my display() is correct.
void display(N *p) {
N *current;
current = p;
while (current != NULL) {
printf("\n%d", current->data);
current = current->next;
}
}
Your malloc(sizeof(p)) only returns enough space for a pointer. You instead want malloc(sizeof(N)).
Also, you need to return the new value of p instead of throwing it away at the end of add(). (Your start has a similar issue; pick one to be the head of your linked list.)
There are problems:
function add() does not allocate the correct amount of memory. Use this method:
current = malloc(sizeof(*current));
The way you are inserting the newly allocated object into the list does not work: you modify p, which is an argument with local scope, and you set start which also has local scope. No side effect is performed on the N pointer is the callers scope.
Your display function is correct, but I would favor adding the newline at the end of the output instead of at the beginning.
Here is an updated version with a better API:
int add(N **headp) {
N *current = calloc(sizeof(*current));
if (current == NULL) {
fprintf(stderr, "cannot allocate memory for new object\n");
return -1;
}
if (scanf("%d", &current->data) != 1) {
fprintf(stderr, "cannot read value for new object\n");
return -2;
}
current->next = *headp;
*headp = current;
return 0;
}
void display(const N *list) {
for (const N *p = list; p != NULL; p = p->next) {
printf("%d\n", p->data);
}
}
The add function is used this way from the caller:
#include <stdio.h>
#include <stdlib.h>
typedef struct N {
int data;
struct N *next;
} N;
int main(void) {
N *list = NULL;
for (i = 0; i < 10; i++) {
if (add(&list))
break;
}
display(list);
return 0;
}

Removal of items with duplicate data

I'm writing a function that removes the consecutive items with duplicate data .
e.g
For example, passing in the list
->a->b->c->c->a->b->b->b->a->null
should result in
->a->b->c->a->b->a->null
The list item definition and function declaration are given below
struct litem {
char data;
litem* next;
};
Mo code looks like
int remove_dumplicates(litem *&list)
{
int count = 0;
struct litem * current = NULL;
current = list;
struct litem *deleteNode;
if (current == NULL ) return;
while(current->next != NULL)
{
if ( current->data == current->next->data) // check for the duplicates
{
count++;
deleteNode =current->next;
current>next= current->next->next;
delete deleteNode;
}
return (count);
}
}
Is this a correct way of achieving the desired result ?
I don't see current being incremented to current->next.
Take as an example a list with all unique elements a -> b -> c and see how your program works.
To fix this you need:
while(current->next != NULL) {
if ( current->data == current->next->data) {
// delete duplicates .
} else {
current = current -> next;
}
}// end-while
return (count);
You need to add an else inside the while loop to advance to the next node:
if( current-> data == current->next->data ) {
....
} else {
current = current->next;
}
Also the returns need to be fixed (the first should return 0 and the second should be moved outside the while loop).
Some quick observations:
The return (count) statement might be outside the while loop, otherwise the loop would be terminated prematurely.
A statement like current = current->next; is required inside the while loop. Otherwise, the loop would become an infinite loop.
current should move to current->next on no duplicate match.
Argument passed to the function should be merely *list (ie. a pointer to an element of type struct litem)
delete is a C++ keyword. Use free() instead.
The modified code:
int remove_duplicates(struct litem *list)
{
int count = 0;
struct litem * current = NULL;
current = list;
struct litem *deleteNode;
if (current == NULL ) return;
while(current->next != NULL)
{
if ( current->data == current->next->data)
{
count++;
deleteNode = current->next;
current->next= current->next->next;
free(deleteNode);
}
else
{
current = current->next;
}
}
return (count);
}
Try this:
int remove_duplicates(litem *&list)
{
int count = 0;
struct litem * current = NULL;
current = list;
struct litem *deleteNode;
if (current == NULL ) return 0;
while(current->next != NULL)
{
if (current->data == current->next->data) // check for the duplicates
{
count++;
deleteNode =current->next;
current->next= current->next->next;
delete deleteNode;
}
else
{
current = current->next;
}
}
return (count);
}

Resources