如何避免C中的自引用链表

时间:2018-04-17 03:55:38

标签: c struct linked-list singly-linked-list

我正在为我的操作系统课程编写这个程序而且我仍然坚持看似简单的问题。我有一个Lock结构和一个lockList结构,它包含一个指向Lock的指针作为其头部。当我需要向列表中添加锁时,我需要将其添加到链表的末尾并能够打印它们。问题是当我添加其中两个(添加一个工作正常),然后用"列表"打印它。我写的命令,它打印了我无限添加的第二件事。我确定这是因为第二个Lock" next"字段指向自身,我无法弄清楚为什么或如何解决它。

这是我添加锁的代码:

if (lockList.head == NULL) {
    Lock lock = {.next = NULL}; 
    strcpy(lock.name, name);
    lockList.head = &lock;
  } else {
    while (contains(name)) {
      pthread_cond_wait(&cond, &mutex);
    }

    Lock *current = lockList.head;
    while (current->next != NULL) {
      current = current->next;
    }

    Lock lock = {.next = NULL}; 
    strcpy(lock.name, name);

    current->next = &lock;
  }

My Lock和lockList结构:

typedef struct Lock {
  char name[25];
  struct Lock *next;
} Lock;

struct LockList {
  Lock *head;
}lockList;

和我的代码列出列表中的项目:

else if (strcmp(cmd, "list") == 0) {
  Lock *current = lockList.head;

  while (current != NULL) {
    fprintf(fp, "%s\n", current->name);
    current = current->next;
  } 

}

完整代码:

#include <stdio.h>
#include <stdbool.h>
#include <stdlib.h>
#include <string.h>
#include <pthread.h>
#include <sys/socket.h>
#include <sys/types.h>
#include <unistd.h>
#include <arpa/inet.h>
#include <netdb.h>
#include <signal.h>
#include <errno.h>

/** Port number used by my server */
#define PORT_NUMBER "26136"

pthread_mutex_t mutex;
pthread_cond_t cond;

// Print out an error message and exit.
static void fail( char const *message ) {
  fprintf( stderr, "%s\n", message );
  exit( 1 );
}



typedef struct Lock {
  char name[25];
  struct Lock *next;
} Lock;

struct LockList {
  Lock *head;
}lockList;

bool contains(char title[]) {
  Lock *current = lockList.head;
  while (current != NULL) {
    if (current->name == title) {
      return true;
    }
    current = current->next;
  }

  return false;
}

/** handle a client connection, close it when we're done. */
void handleClient( int sock ) {
  // Here's a nice trick, wrap a C standard IO FILE around the
  // socket, so we can communicate the same way we would read/write
  // a file.
  FILE *fp = fdopen( sock, "a+" );

  // Prompt the user for a command.
  fprintf( fp, "cmd> " );

  char cmd[ 11 ];
  int match;
  while ( ( match = fscanf( fp, "%s", cmd ) ) == 1 &&
          strcmp( cmd, "quit" ) != 0 ) {

    // if command was lock
    if (strcmp(cmd, "lock") == 0) {
      // lock mutex
      pthread_mutex_lock(&mutex);

      char name[25];
      fscanf(fp, "%s", name);

      // while the thing requested is on the locked list, wait      


      // add the new lock to the locked list
      if (lockList.head == NULL) {
        Lock lock = {.next = NULL}; 
        strcpy(lock.name, name);
        lockList.head = &lock;
      } else {
        while (contains(name)) {
          pthread_cond_wait(&cond, &mutex);
        }

        Lock *current = lockList.head;
        while (current->next != NULL) {
          current = current->next;
        }

        Lock lock = {.next = NULL}; 
        strcpy(lock.name, name);

        current->next = &lock;
      }

      // unlock mutex
      pthread_mutex_unlock(&mutex);
    } else if (strcmp(cmd, "unlock") == 0) {

      // lock mutex
      pthread_mutex_lock(&mutex);

      char name[25];
      fscanf(fp, "%s", name);
      // if item with that name is in the list, take it off
      Lock *current = lockList.head;

      if (strcmp(lockList.head->name, name) == 0) {
        lockList.head = lockList.head->next;
      } else {
        while (current->next != NULL) {
          if (strcmp(current->next->name, name) == 0) {
            // if item found is in the middle of the list
            current->next = current->next->next;
            break;        
          }
          current = current->next;
        }
      }

      // broadcast the condition variable
      pthread_cond_broadcast(&cond);

      // unlock mutex
      pthread_mutex_unlock(&mutex);
    } else if (strcmp(cmd, "list") == 0) {
      Lock *current = lockList.head;

      while (current != NULL) {
        fprintf(fp, "%s\n", current->name);
        current = current->next;
      } 

    } else {
      fprintf(fp, "invalid command");
    }



    // Prompt the user for the next command.
    fprintf( fp, "cmd> " );
    fflush( fp );
  }

  // Close the connection with this client.
  fclose( fp );
}

int main() {
  lockList.head = NULL;


  pthread_mutex_init(&mutex, NULL);
  pthread_cond_init(&cond, NULL);
  // Prepare a description of server address criteria.
  struct addrinfo addrCriteria;
  memset(&addrCriteria, 0, sizeof(addrCriteria));
  addrCriteria.ai_family = AF_INET;
  addrCriteria.ai_flags = AI_PASSIVE;
  addrCriteria.ai_socktype = SOCK_STREAM;
  addrCriteria.ai_protocol = IPPROTO_TCP;

  // Lookup a list of matching addresses
  struct addrinfo *servAddr;
  if ( getaddrinfo( NULL, PORT_NUMBER, &addrCriteria, &servAddr) )
    fail( "Can't get address info" );

  // Try to just use the first one.
  if ( servAddr == NULL )
    fail( "Can't get address" );

  // Create a TCP socket
  int servSock = socket( servAddr->ai_family, servAddr->ai_socktype,
                         servAddr->ai_protocol);
  if ( servSock < 0 )
    fail( "Can't create socket" );

  // Bind to the local address
  if ( bind(servSock, servAddr->ai_addr, servAddr->ai_addrlen) != 0 )
    fail( "Can't bind socket" );

  // Tell the socket to listen for incoming connections.
  if ( listen( servSock, 5 ) != 0 )
    fail( "Can't listen on socket" );

  // Free address list allocated by getaddrinfo()
  freeaddrinfo(servAddr);

  // Fields for accepting a client connection.
  struct sockaddr_storage clntAddr; // Client address
  socklen_t clntAddrLen = sizeof(clntAddr);

  while ( true  ) {
    // Accept a client connection.
    int sock = accept( servSock, (struct sockaddr *) &clntAddr, &clntAddrLen);

    // Talk to this client
    handleClient( sock );
  }

  // Stop accepting client connections (never reached).
  close( servSock );

  return 0;
}

这是真正的MCVE的样子:

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

typedef struct Lock {
    char name[25];
    struct Lock *next;
} Lock;

struct LockList {
    Lock *head;
}
lockList;

int main(void)
{
    lockList.head = NULL;
    char *str[] = { "world", "hello" };
    for (int i = 0; i < 2; i++)
    {
        Lock lock = {.next = lockList.head};
        strcpy(lock.name, str[i]);
        lockList.head = &lock;
    }
    printf("%s\n", lockList.head->name);
    printf("%s\n", lockList.head->next->name);
}

此计划的预期输出

  

您好
  世界

实际输出是

  

您好
  喂

我会让其他人解释为什么会这样。

0 个答案:

没有答案