0

Create a function that receives two Lists (L1,L2), initialize L2, and insert in L2 the elements of L1 excluding the ones in odd postion (Assume that the first element of the list is in position zero). Then print L2.

My prof gave us the solution (below), but I need to create a main() that calls this function and returns L2, and since I'm a newbie nothing seems to work.

I tried initializing L1 and then calling the function, but all I got was a huge amount of errors.

That's the final function:

struct list{
    int value;
    struct list * nextPtr;
};
void createSubList(struct list * l1Ptr, struct list ** l2PtrPtr) {
    init(l2PtrPtr);
    while(l1Ptr!=NULL) {
        pre_insert(l2PtrPtr, l1Ptr­>value);
        l1Ptr = l1Ptr­>nextPtr;
        if (l1Ptr != NULL)
            l1Ptr = l1Ptr­>nextPtr;
    }
}

I expect to see L2 printed after calling the function. That's my final file:

#include <stdlib.h> 
#include <string.h> 



struct list {
    int value;
    struct list *nextPtr;

    };


void init( struct list **ptrptr){
    *ptrptr!=NULL;

}
void prn (struct list * lptr) { 
    while (lptr) { 
        printf (" %d", lptr->value); 
        lptr = lptr->nextPtr; 
    } 
    putchar ('\n'); }
void pre_insert(struct list ** ptrptr, int value){
    struct list * tmp_ptr;
    tmp_ptr=*ptrptr;
    *ptrptr=(struct list *)malloc(sizeof(struct list));
    (*ptrptr)->value=value;
    (*ptrptr)->nextPtr=tmp_ptr;
}

   void createSubList(struct list* l1Ptr, struct list** l2PtrPtr) {
    init(l2PtrPtr);
    while(l1Ptr!=NULL) {
        pre_insert(l2PtrPtr, l1Ptr->value);
        l1Ptr = l1Ptr->nextPtr;
        if (l1Ptr != NULL)
            l1Ptr = l1Ptr->nextPtr;
    }
    prn(l1Ptr);
    }



void main(){
    struct list* l1Ptr; 
    init(&l1Ptr);
    struct list* l2ptr; 
    init(&l2ptr);
    pre_insert(&l1Ptr , 1);
    pre_insert(&l1Ptr , 2);
    pre_insert(&l1Ptr , 3);
    pre_insert(&l1Ptr , 4);
    pre_insert(&l1Ptr , 5);
    pre_insert(&l1Ptr , 6);
    createSubList(l1Ptr,&l2ptr);


}



Errors I get:

[Finished in 0.1s with exit code -11]
[shell_cmd: gcc "/home/vittorio/Scrivania/CProjects/new.c" -o "/home/vittorio/Scrivania/CProjects/new" && "/home/vittorio/Scrivania/CProjects/new"]
[dir: /home/vittorio/Scrivania/CProjects]
[path: /home/vittorio/bin:/home/vittorio/.local/bin:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/usr/games:/usr/local/games:/snap/bin]
  • 1
    `struct list ** l2PtrPtr` you need to pass `createSubList(l1Ptr, &l2ptr);` (note the `'&'` before the 2nd parameter) You still need to write the `print` function. `createSubList` just sews the lists together per your algorithm, it doesn't output anything. Additionally, please provide [A Minimal, Complete, and Verifiable Example (MCVE)](http://stackoverflow.com/help/mcve). Much of your functions are missing. – David C. Rankin Apr 23 '19 at 08:53
  • First of all thanks for your quick reply! I couldn't write the ending part of the function (the one that prints L2 in return), cause all the solutions I've found in the web implements some functions or some expressions we haven't studied in class. – Mark Sorensen Apr 23 '19 at 09:06
  • If they are just linked-lists, then pass a pointer and iterate until your current pointer is `NULL`, e.g. `void prn (struct list * lptr) { while (lptr) { printf (" %d", lptr->value); lptr = lptr->next; } putchar ('\n'); }` Then call it with, e.g. `prn (l1Ptr);` same for your other pointer. – David C. Rankin Apr 23 '19 at 09:10
  • 1
    E.g. `stray ‘\302’ in program` your program has some wild character-set that isn't flat ASCII. Most likely you have long em-dashes or left/right double-quotes from copying from a web-page (or rich-text editor). Just copy/paste your code into an TEXT editor that will save in flat-ASCII and those errors will go away. You may have to fix a couple of the characters manually. See [Compilation error: stray '\302' in program etc](https://stackoverflow.com/questions/19198332/compilation-error-stray-302-in-program-etc) – David C. Rankin Apr 23 '19 at 09:16
  • Thanks David, it really was an ASCII problem. I updated the code and the errors in the topic, implementing your function. Still I can't get the second list printed – Mark Sorensen Apr 23 '19 at 09:38

2 Answers2

0

Once you get the non-ASCII chars squared away. Take your implementation piece-by-piece. For starters, unless you are on a non-conforming system, the proper declarations for main are int main (void) and int main (int argc, char **argv) (which you will see written with the equivalent char *argv[]). note: main is a function of type int and it returns a value. See: C11 Standard §5.1.2.2.1 Program startup p1 (draft n1570). See also: What should main() return in C and C++?.

So, for conforming implementation, main() without arguments should be:

int main (void) {

    struct list *l1Ptr = NULL; 
    struct list *l2ptr = NULL; 
    ...

(note: just ditch your init() function, you don't need to function call overhead just to set a pointer NULL)

Next issue along the way is your pre_insert must distinguish between adding the 1st node to the list, and adding all others. For the 1st node, just set your *ptrptr to your initialize tmp_ptr to establish the head of the list. For the remaining nodes, you are using chaining where you set tmp_ptr->nextPtr = *ptrptr; to make the next pointer in the new node point to the old-start of your list, then set *ptrptr = tmp_ptr; to make it your new start of the list, e.g.

void pre_insert (struct list **ptrptr, int value)
{
    struct list *tmp_ptr = malloc (sizeof *tmp_ptr); /* don't cast malloc */
    if (tmp_ptr == NULL) {                  /* validate EVERY allocation */
        perror ("malloc-tmp_ptr");
        exit (EXIT_FAILURE);
    }
    tmp_ptr->value = value;         /* initialize struct members */
    tmp_ptr->nextPtr = NULL;

    if (!*ptrptr)                   /* if 1st node, simply assign */
        *ptrptr = tmp_ptr;
    else {
        tmp_ptr->nextPtr = *ptrptr; /* otherwise, set tmp->next to 1st */
        *ptrptr = tmp_ptr;          /* now set list to point to tmp */
    }
}

Your createSubList had similar redundant logic, showing your were struggling. All you need is a simply 1/0 toggle to add or skip nodes from list1. For example:

void createSubList (struct list *l1Ptr, struct list **l2PtrPtr)
{
    int i = 0;

    while (l1Ptr != NULL) {
        if (i == 0) {       /* only store even nodes */
            pre_insert (l2PtrPtr, l1Ptr->value);
            i = 1;
        }
        else
            i = 0;
        l1Ptr = l1Ptr->nextPtr;
    }
}

As discussed in the comments, you need a way to print your lists, and equally important, a way to free the memory allocated to the nodes where you are done with them. Simple functions are all you need, e.g.

void prnlist (struct list *lptr)
{
    while (lptr) {
        printf (" %d", lptr->value);
        lptr = lptr->nextPtr;
    }
    putchar ('\n');
}

void freelist (struct list *lptr)
{
    while (lptr) {
        struct list *victim = lptr;
        lptr = lptr->nextPtr;
        free (victim);
    }
}

(note: do you see why you have to save a pointer to the current node, and then advance the node before calling free on your victim?)

That's it, aside from my additional comments in-line. Putting it altogether you could do:

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

struct list {
    int value;
    struct list *nextPtr;
};

void pre_insert (struct list **ptrptr, int value)
{
    struct list *tmp_ptr = malloc (sizeof *tmp_ptr); /* don't cast malloc */
    if (tmp_ptr == NULL) {                  /* validate EVERY allocation */
        perror ("malloc-tmp_ptr");
        exit (EXIT_FAILURE);
    }
    tmp_ptr->value = value;         /* initialize struct members */
    tmp_ptr->nextPtr = NULL;

    if (!*ptrptr)                   /* if 1st node, simply assign */
        *ptrptr = tmp_ptr;
    else {
        tmp_ptr->nextPtr = *ptrptr; /* otherwise, set tmp->next to 1st */
        *ptrptr = tmp_ptr;          /* now set list to point to tmp */
    }
}

void createSubList (struct list *l1Ptr, struct list **l2PtrPtr)
{
    int i = 0;

    while (l1Ptr != NULL) {
        if (i == 0) {       /* only store even nodes */
            pre_insert (l2PtrPtr, l1Ptr->value);
            i = 1;
        }
        else
            i = 0;
        l1Ptr = l1Ptr->nextPtr;
    }
}

void prnlist (struct list *lptr)
{
    while (lptr) {
        printf (" %d", lptr->value);
        lptr = lptr->nextPtr;
    }
    putchar ('\n');
}

void freelist (struct list *lptr)
{
    while (lptr) {
        struct list *victim = lptr;
        lptr = lptr->nextPtr;
        free (victim);
    }
}

int main (void) {

    struct list *l1Ptr = NULL; 
    struct list *l2ptr = NULL; 

    for (int i = 1; i < 10; i++)
        pre_insert (&l1Ptr , i);

    createSubList (l1Ptr, &l2ptr);

    prnlist (l2ptr);    /* print list 2 */

    freelist (l1Ptr);   /* don't forget to free what you allocate */
    freelist (l2ptr);
}

Example Use/Output

$ ./bin/llcreatesublist
 1 3 5 7 9

Memory Use/Error Check

In any code you write that dynamically allocates memory, you have 2 responsibilities regarding any block of memory allocated: (1) always preserve a pointer to the starting address for the block of memory so, (2) it can be freed when it is no longer needed.

It is imperative that you use a memory error checking program to insure you do not attempt to access memory or write beyond/outside the bounds of your allocated block, attempt to read or base a conditional jump on an uninitialized value, and finally, to confirm that you free all the memory you have allocated.

For Linux valgrind is the normal choice. There are similar memory checkers for every platform. They are all simple to use, just run your program through it.

$ valgrind ./bin/llcreatesublist
==23324== Memcheck, a memory error detector
==23324== Copyright (C) 2002-2015, and GNU GPL'd, by Julian Seward et al.
==23324== Using Valgrind-3.12.0 and LibVEX; rerun with -h for copyright info
==23324== Command: ./bin/llcreatesublist
==23324==
 1 3 5 7 9
==23324==
==23324== HEAP SUMMARY:
==23324==     in use at exit: 0 bytes in 0 blocks
==23324==   total heap usage: 14 allocs, 14 frees, 224 bytes allocated
==23324==
==23324== All heap blocks were freed -- no leaks are possible
==23324==
==23324== For counts of detected and suppressed errors, rerun with: -v
==23324== ERROR SUMMARY: 0 errors from 0 contexts (suppressed: 0 from 0)

Always confirm that you have freed all memory you have allocated and that there are no memory errors.

Look things over and let me know if you have further questions.

David C. Rankin
  • 81,885
  • 6
  • 58
  • 85
  • David, you're a blessing! I understood more with your example than studying 3 hours on my book. It works! Thanks a lot for your time! – Mark Sorensen Apr 23 '19 at 12:38
0
  • You need to add #include <stdio.h>

  • In the init function the code *ptrptr!=NULL; shall be *ptrptr=NULL;, i.e. no !

  • Then change void main(){ to int main(){

That should solve the warnings.

Then you need to do the actual printing. So in main do:

prn(l1Ptr);
createSubList(l1Ptr,&l2ptr);
prn(l2ptr);

BTW: Notice that the prn(l1Ptr); inside createSubList will not print anything as l1Ptr is already NULL when you call prn. So you should simply delete that line.

With the above change your output should be:

 6 5 4 3 2 1
 2 4 6

The created sub-list is reverted compared to the original list due to use of pre_insert that adds new nodes in the front.

Support Ukraine
  • 42,271
  • 4
  • 38
  • 63