Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
515 views
in Technique[技术] by (71.8m points)

struct - Using functions in C, declaring a variable and using it in multiple functions

I want to make a linked list that is called from my main somewhere else. This linked list is made of nodes.

For example, this isn't my code just simplified version of it.

nodeTest.h

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

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

Then I have another file trying to use that struct:

nodeTest.c

 #include <stdio.h>
 #include <stdlib.h>
 #include "nodeTest.h"

 int main(void) {
     struct nodeTest* first = malloc(sizeof(struct nodeTest));
     first->data = 0;
     return 0;
 }

void addLL(int data){
    if (first.data = 0)
    {
        printf("No head
");
    }
}

I want first to be the first element in a linked list so how do I define an addElement to it that utilizes first? Right now when I call first I am getting an unrecognized error.

Here is where I get the error inside my linked list file after the main

void addLL(int data){
    if (head.data = 0)

I get the error at the if line, head is not recognized.

See Question&Answers more detail:os

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Reply

0 votes
by (71.8m points)

Right. You get that error because the variable head is only visible from inside main. There are two ways around this:

  1. You can declare head as a global variable, outside of any functions; or
  2. You can pass head to any functions that need it as a pointer

Let's see how these options work:

Using a global variable

#include <stdio.h>
#include <stdlib.h>
#include "nodeTest.h"

/* Declare a global variable. The initialization to NULL is redundant
 * since global variables are automatically initialized to zero. But
 * let's be thorough.
 */

struct nodeTest* head = NULL;

int main(void) {
   head = malloc(sizeof(struct nodeTest));
   /* check if head is NULL here. Just in case. */
   head->data = 0;

   addLL(1);

   return 0;
}

/* other functions here */
void addLL(int data) {
   /* since we allocate head in main it should never be NULL and
    * if it is, something is wrong. So assert.
    */
   assert(head != NULL);

   /* Notice: in your original code you had: if (first.data = 0)
    * which is wrong. First of all, there's no variable named first
    * declared anywhere. If you meant head, that should have been
    * head->first since head is a pointer. And lastly, first.data = 0
    * would set first.data to 0, instead of comparing it for equivalency, 
    * and would then cause the if to never execute because the compiler
    * would first set first.data to zero, then check first.data, and never
    * enter the loop since it was zero.
    */
   if (head->data == 0)
   {
      printf("No head");
      return;
   }

   /* other code here */
}

This version is easy and requires minimal changes. A benefit is that functions that need to modify head can easily do it.

It does require, in non-trivial programs, a lot of global variables though, which is considered bad programming practice and ought to be avoided if possible.

Passing head as a pointer

#include <stdio.h>
#include <stdlib.h>
#include "nodeTest.h"

int main(void) {
   struct nodeTest* head = malloc(sizeof(struct nodeTest));
   /* check if head is NULL here. Just in case. */
   head->data = 0;

   /* we call addLL, passing the head that we just allocated
    * to it.
    */
   addLL(1, head);
   return 0;
}

void addLL(int data, struct nodeTest *head) {
   if (head == NULL) || (head->data == 0))
   {
      printf("No head");
      return;
   }

   /* other code here */
}

This method requires that we pass head into every function that can need it. This complicates the function interface slightly but allows us more flexibility because we don't need to have many global variables for the many lists we'll have in our program.

But there is another problem. If any of those functions needs to modify the head pointer (for example, let's say you're deleting the first element in a list) then you have an issue. The pointer (which is distinct from the thing pointed to) is local to the function so any changes made to it will be invisible outside the function.

There are two ways to get around this issue:

  1. Every function that accepts head as a parameter and may need to change it would have to return a pointer to the new head. This works but it can be cumbersome to implement and very prone to error.
  2. Every function that accepts head as a parameter and may need to change it would accept a double pointer: a pointer to a pointer to the head. This works well but complicates things and may catch some novice programmers off-guard. It's also a bit prone to error but not as much as the previous option.

I hope that this answers your question, explains why you can't do what you did and the workarounds that exist.


与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
OGeek|极客中国-欢迎来到极客的世界,一个免费开放的程序员编程交流平台!开放,进步,分享!让技术改变生活,让极客改变未来! Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...