I am almost certain that I got this wrong, but I'm not sure how it would be right. It currently doesn't compile, but it is more the concept I am looking for. Pointers are the only things really confusing me in C right now (Although I'm sure other things will come). Anyways, I am just trying to do the first couple of functions for Linked Lists from my book. It would be great if someone could give some small code (and explain it), because that seems to be the way that I learn this sort of thing.
Code:
#include <stdio.h>

typedef struct NODE {
        int data;
        NODE* next;
};
// Function prototypes:
void DisplayList(NODE* head);
void Insert(NODE* head, int value);

void main() {
        NODE* head = 0;
        Insert(head, 10);
        Insert(head, 20);
        Insert(head, 30);

        DisplayList(head);
}

void DisplayList( NODE* head ) {
        NODE* node;

        for(node = head; node; node = node->next) {
                printf("%d\n",node->data);
        }
}

void Insert(NODE* head, int value) {
        NODE* newnode;

        newnode = malloc(sizeof(struct NODE));
        if( !newnode )
                return 0;
        newnode->data = value;

        newnode->next = head;
        head = newnode;

        return 1;
}
Sorry for the bad code :/

Edit: Rather than giving random code that is probably hard to follow, I'll just ask some general questions: If I want to pass a pointer to a routine and be able to edit the pointer as well as the data at that pointer, how would I do it? If I wanted to pass a variable to a function and have it be edited and the edit remain after the function, would I do it similar to this:

Code:
void main() {
  int a = 5;
  MultByFive( &a );
}
void MultByFive( *value ) {
  *value = *value * 5;
}
How would I just pass an array and edit the values in a function?
_player1537 wrote:

Code:
typedef struct NODE {
        int data;
        NODE* next;
};


Your typedef is wrong. What you want to name a type goes *AFTER* the type. As it is now, you are declaring a struct NODE, and then not giving it a name.

Quote:
Edit: Rather than giving random code that is probably hard to follow, I'll just ask some general questions: If I want to pass a pointer to a routine and be able to edit the pointer as well as the data at that pointer, how would I do it?


Use a pointer to a pointer.


Code:
void whatever(char **out) {
*out = "whatever";
}

void someotherfunc() {
char *message;
whatever(&message);
}


Note, though, that this isn't a great pattern. It can complicate things (such as who is responsible for freeing the data the pointer points to, or even if it should be freed at all - it could be pointing at a global or something).

Quote:
If I wanted to pass a variable to a function and have it be edited and the edit remain after the function, would I do it similar to this:
Code:
void main() {
  int a = 5;
  MultByFive( &a );
}
void MultByFive( *value ) {
  *value = *value * 5;
}


Yes - why didn't you just try that?

Quote:
How would I just pass an array and edit the values in a function?


An array is just a pointer. Any changes to it in a function are stored in the array itself, a copy is not made.

Code:
void replace(char* string, int pos) {
string[pos] = 'a';
}
player_: I've added in comments so it's easier to follow


Code:
#include <stdio.h>
#include <stdlib.h> /* Now we can use macros like NULL and EXIT_SUCCESS */

struct node {
   int data;
   struct node *next;
};

typedef struct node * NodePtr; /* Now we can use the moniker "NodePtr"
                        instead of "struct node *" everywhere */

/* Function prototypes: */
void DisplayList(NodePtr head);
NodePtr Insert(NodePtr head, int value);

int main() {
   NodePtr head = NULL;
   head = Insert(head, 10); /* Update head of list whenever you do something to the list */
   head = Insert(head, 20);
   head = Insert(head, 30);

   DisplayList(head); /* Should display "30\n20\n10\n" */
   return EXIT_SUCCESS;
}

void DisplayList(NodePtr head) {
   NodePtr temp;
   for(temp = head; temp != NULL; temp = temp->next) { /* Make sure to check if node is NULL; trying to dereference a null pointer is very bad */
      printf("%d\n",temp->data);
   }
}

NodePtr Insert(NodePtr head, int value) {
   NodePtr newnode = (NodePtr)malloc(sizeof(*newnode)); /* Create a new node */
   /* if( !newnode )  What were you trying to do here?
      return 0;  Can't return an integer when the return type is void */
   newnode->data = value;
   newnode->next = head;
   head = newnode;
   return head; /* Since we're changing the head of the list,
               we'll return a pointer to the new head of the list */
}
Ultimate Dev'r wrote:

Code:
typedef struct node * NODE; /* Now we can use the moniker "NODE"
                        instead of "struct node *" everywhere */


BAD BAD BAD

Never ever typedef a pointer. Hiding that something is a pointer is such a terrible idea. Also, all caps is for macros only.

"typedef struct node node_t;" would be what you want.
Kllrnohj wrote:
Never ever typedef a pointer. Hiding that something is a pointer is such a terrible idea. Also, all caps is for macros only.

"typedef struct node node_t;" would be what you want.


My bad; should be "typedef struct node * NodePtr". Code above has been updated.
Ultimate Dev'r wrote:
My bad; should be "typedef struct node * NodePtr". Code above has been updated.


At least it isn't hidden now, but it is still much better to not typedef the pointer at all. Just typedef the struct, and use "node_t*" instead. There are two big reasons:

1) All your pointers are then visually consistent. You can just scan for * to quickly find pointers. There is no reason to hide a language-level concept behind a typedef.

2) The way it is now prevents you from making nodes on the stack using the typedef. This leads to inconsistency between using "NodePtr" most of the time, and "struct node" some of the time.

Since there are approximately 0 reasons to typedef the pointer, we come back to my original statement - don't do it. Just don't, it's useless, ugly, and not standard practice.
Kllrnohj wrote:
Ultimate Dev'r wrote:
My bad; should be "typedef struct node * NodePtr". Code above has been updated.


At least it isn't hidden now, but it is still much better to not typedef the pointer at all. Just typedef the struct, and use "node_t*" instead. There are two big reasons:

1) All your pointers are then visually consistent. You can just scan for * to quickly find pointers. There is no reason to hide a language-level concept behind a typedef.

2) The way it is now prevents you from making nodes on the stack using the typedef. This leads to inconsistency between using "NodePtr" most of the time, and "struct node" some of the time.

Since there are approximately 0 reasons to typedef the pointer, we come back to my original statement - don't do it. Just don't, it's useless, ugly, and not standard practice.


These are both good points, but as far as this being "useless, ugly, and not standard practice", take a look at pg. 146 of K&R; it typedefs a pointer the same way in their linked list examples as I have.
Kllrnohj wrote:
_player1537 wrote:

Code:
typedef struct NODE {
        int data;
        NODE* next;
};


Your typedef is wrong. What you want to name a type goes *AFTER* the type. As it is now, you are declaring a struct NODE, and then not giving it a name.
Ah, okay. I had thrown that in as a last effort to get it to compile. Thanks, though I probably should have googled how to typedef something :/

Quote:
Quote:
Edit: Rather than giving random code that is probably hard to follow, I'll just ask some general questions: If I want to pass a pointer to a routine and be able to edit the pointer as well as the data at that pointer, how would I do it?


Use a pointer to a pointer.


Code:
void whatever(char **out) {
*out = "whatever";
}

void someotherfunc() {
char *message;
whatever(&message);
}
If I wanted to read the 2nd character ("h"), would I do:
Code:
void whatever(char **out) {
   *out = "whatever";
   printf("%c",*out[1]);
}
void someotherfunc() {
char *message;
whatever(&message);
}


Quote:
Note, though, that this isn't a great pattern. It can complicate things (such as who is responsible for freeing the data the pointer points to, or even if it should be freed at all - it could be pointing at a global or something).
Okay, thanks Smile

Quote:
Quote:
If I wanted to pass a variable to a function and have it be edited and the edit remain after the function, would I do it similar to this:
Code:
void main() {
  int a = 5;
  MultByFive( &a );
}
void MultByFive( *value ) {
  *value = *value * 5;
}


Yes - why didn't you just try that?
Because I didn't want to be wrong and mess my computer up.


Quote:
Quote:
How would I just pass an array and edit the values in a function?


An array is just a pointer. Any changes to it in a function are stored in the array itself, a copy is not made.

Code:
void replace(char* string, int pos) {
string[pos] = 'a';
}
Ah, that makes sense.

Ultimate Dev'r wrote:
player_: I've added in comments so it's easier to follow

code removed
I was really confused when I first saw that because (for some reason) I misread the typedef and saw the asterisk as a wild card instead of a pointer. After I noticed that, it was a little easier to follow, though the backwards (in my mind) way of it being a pointer normally made it pretty difficult too. (That was when it still read NODE instead of NodePtr)

If I were to make the Insert function automatically edit the head variable (so you don't have to do head = Insert(), just Insert()), would this be correct?

Code:
void Insert(NodePtr* head, int value) {
   NodePtr newnode = (NodePtr)malloc(sizeof(*newnode)); /* Create a new node */
   /* if( !newnode )  What were you trying to do here?
      return 0;  Can't return an integer when the return type is void */
   newnode->data = value;
   newnode->next = head;
   *head = *newnode;
}
And then just calling it like
Code:
Insert(*head, 30);
Or is that completely wrong?

Code:
void Insert(NodePtr* head, int value) {
/*Method body */
}

If you insist on creating a typedef with a pointer in it, remember not to put another asterisk Wink That should be "NodePtr head" as far as I can tell from context.
But when the routine is called, it will push a pointer that I use through the routine, but the second that routine is over, I lose the pointer. So any changes I make to it, I lose. By pushing a pointer to a pointer, I should be able to edit the pointer to a node, which is what I'd have to do with the Insert() function. Or is that wrong?
Here's my corrections to your Insert function:

Code:
void Insert(NodePtr* head, int value) {
   NodePtr newnode = (NodePtr)malloc(sizeof(*newnode)); /* Create a new node */
   newnode->data = value;
   newnode->next = *head; /* Dereference head because we passed in the a pointer to head */
   *head = newnode; /* Same thing here */
}


Also, you'd need to update your funtion prototype accordingly.

wrote:
And then just calling it like
Code:
Insert(*head, 30);
Or is that completely wrong?


Actually you would call

Code:
Insert(&head, 20);
because you want to pass the address of the pointer ("point to the pointer"), not dereference it (passing the value pointed to by the pointer).

wrote:
But when the routine is called, it will push a pointer that I use through the routine, but the second that routine is over, I lose the pointer. So any changes I make to it, I lose. By pushing a pointer to a pointer, I should be able to edit the pointer to a node, which is what I'd have to do with the Insert() function. Or is that wrong?


This is correct.

As I'm sure Kllrnohj will point out, once we have multiple layers of pointers like this, typedef'ing "struct node *" isn't such a good idea anymore, as clarity is significantly reduced.
Ah, okay.
In that case, your final assignment needs to be "*head = newnode".
Also, as a question to anyone, would sizeof(NodePtr) or sizeof(newnode) be considered better?
Edit: Oh, I also missed the other assignment, and was ninja'd.
calcdude84se wrote:
Ah, okay.
In that case, your final assignment needs to be "*head = newnode".
Also, as a question to anyone, would sizeof(NodePtr) or sizeof(newnode) be considered better?
Edit: Oh, I also missed the other assignment, and was ninja'd.


I used sizeof(*newnode) because it dereferences the pointer and is thusly equivalent to sizeof(struct node).
Oh, whoops, using sizeof(NodePtr) wouldn't work. I think the typedef'ing caught me up.
calcdude84se wrote:
Oh, whoops, using sizeof(NodePtr) wouldn't work. I think the typedef'ing caught me up.


Normally I don't typedef pointers, but seeing as how quite a few people use typedef'd pointers to teach linked lists for easier understanding (my professor and K&R included), I thought it would do the same, but apparently it's just confusing everyone Razz
Does this look right for a Delete() function:
Code:
void Delete(NodePtr* head) {
  NodePtr temp = *head;
  NodePtr* prevPtr;
  while(temp != NULL) {
    prevPtr = &temp;
    temp = temp->next;
    free(prevPtr);
  }
}
And you would call it like:
Code:
Delete(&head);
That looks right. Also, because it's bugging me, it's C naming convention to use lowercase function names Wink
Additionally, I don't think you're allowed to declare variables mid-function.
I've been told that I can use whatever styling I want, as long as it is within reason, consistent, and easy to read (to most). Also, from all the C code I have read, it has always been: functions are PascalCased, variables are camelCased, structs are ALL CAPS, and pointers have asterisks after the data type (or at least, that's what I tend to use).

Also, what do you mean about declaring variables mid-function, as far as I know, I can do that.
And this is why I never should have typedef'd a pointer for readability Mad

Your Delete() function should be:


Code:
void Delete(NodePtr* head) {
  NodePtr *temp = head; /* You want to make a copy of head to traverse the list */
  NodePtr prevPtr; /* Pointer to a node; notice there is only 1 asterisk */
  while(temp != NULL) {
    prevPtr = *temp; /* Dereference temp b/c it is a "double pointer" */
    *temp = (*temp)->next; /* Same here */
    free(prevPtr);
  }
}
Can't it just be

Code:
void Delete(NodePtr* head) {
  NodePtr temp = *head;
  NodePtr prevPtr;
  while(temp != NULL) {
    prevPtr = temp;
    temp = temp->next;
    free(prevPtr);
  }
}

No need to add one more layer?
  
Register to Join the Conversation
Have your own thoughts to add to this or any other topic? Want to ask a question, offer a suggestion, share your own programs and projects, upload a file to the file archives, get help with calculator and computer programming, or simply chat with like-minded coders and tech and calculator enthusiasts via the site-wide AJAX SAX widget? Registration for a free Cemetech account only takes a minute.

» Go to Registration page
Page 1 of 2
» All times are UTC - 5 Hours
 
You cannot post new topics in this forum
You cannot reply to topics in this forum
You cannot edit your posts in this forum
You cannot delete your posts in this forum
You cannot vote in polls in this forum

 

Advertisement