如何在C中推和弹出一个空指针

Lan*_*ard 9 c arrays void-pointers flexible-array-member

我有这个工作代码:

#import <stdlib.h>
#import <stdio.h>

typedef struct myarray {
  int len;
  void* items[];
} MYARRAY;

MYARRAY *collection;

void
mypop(void** val) {
  puts(collection->items[collection->len]);
  *val = collection->items[collection->len--];
}

void
mypush(void* val) {
  int len = collection->len++;
  collection->items[len] = val;
  puts(collection->items[len]);
}

int
main() {
  puts("Start");
  collection = malloc( sizeof *collection + (sizeof collection->items[0] * 1000) );
  collection->len = 0;
  puts("Defined collection");
  mypush("foo");
  puts("Pushed foo");
  mypush("bar");
  puts("Pushed bar");
  char str1;
  mypop((void*)&str1);
  puts("Popped bar");
  puts(&str1);
  char str2;
  mypop((void*)&str2);
  puts("Popped foo");
  puts(&str2);
  puts("Done");
  return 0;
}
Run Code Online (Sandbox Code Playgroud)

它输出:

Start
Defined collection
foo
Pushed foo
bar
Pushed bar
(null)
Popped bar

bar
Popped foo
??
Done
Run Code Online (Sandbox Code Playgroud)

它应该输出以下内容:

Start
Defined collection
foo
Pushed foo
bar
Pushed bar
bar
Popped bar
bar
foo
Popped foo
foo
Done
Run Code Online (Sandbox Code Playgroud)

刚开始使用CI时,并不能真正确定发生了什么或为什么输出会被“破坏”。似乎双指针void**允许您传入一个指针并获取一个值而无需知道类型,所以是的。但是想知道是否可以显示该代码应如何实现,以便让我对如何做这样的事情有所了解。

Compiled with clang:

clang -o example example.c
Run Code Online (Sandbox Code Playgroud)

Update

I've updated my code to reflect the latest answers, but still not sure the malloc of the collection is correct.

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

typedef struct myarray {
  int len;
  void* items[];
} MYARRAY;

MYARRAY *collection;

void
mypop(void** val) {
  --collection->len;
  puts(collection->items[collection->len]);
  *val = collection->items[collection->len];
}

void
mypush(void* val) {
  int len = collection->len++;
  collection->items[len] = val;
  puts(collection->items[len]);
}

int
main() {
  puts("Start");
  collection = malloc( sizeof *collection + (sizeof collection->items[0] * 1000) );
  collection->len = 0;
  puts("Defined collection");
  mypush("foo");
  puts("Pushed foo");
  mypush("bar");
  puts("Pushed bar");
  char *str1;
  mypop((void**)&str1);
  puts("Popped bar");
  puts(str1);
  char *str2;
  mypop((void**)&str2);
  puts("Popped foo");
  puts(str2);
  free(collection);
  puts("Done");
  return 0;
}
Run Code Online (Sandbox Code Playgroud)

Rin*_*g Ø 6

有一些问题需要解决,但对于初学者来说还不错。

  1. 流行音乐

您需要先减少len(您的推送在增加后正确执行)。这是一个堆栈。

void mypop(void** val) {
     puts(collection->items[--collection->len]);
     *val = collection->items[collection->len];
}
Run Code Online (Sandbox Code Playgroud)

数组从开始0,所以

len = 0;
items[len++] = elem1;  // len is 0 for the assignment then incremented
items[len++] = elem2;  // len is 1 for the assignment then incremented
Run Code Online (Sandbox Code Playgroud)

然后弹出值

elem2 = items[--len];  // len is first decremented to 1
elem1 = items[--len];  // len is first decremented to 0
Run Code Online (Sandbox Code Playgroud)
  1. 力量

您想要的是一个指向chars的指针,一个char *,for str1str2,因为pop()它将存储一个指针,而不是单个char。

 char *str1;
 mypop((void **)&str1);
 puts("Popped bar");
 puts(str1);
 char *str2;
 mypop((void **)&str2);
 puts("Popped foo");
 puts(str2);
 puts("Done");
 return 0;
Run Code Online (Sandbox Code Playgroud)

那应该修复明显损坏的显示。但是,还有更多有趣的事情

  1. 分配

您的程序之所以运行是因为您的分配量很大,并且items位于内struct,整个分配可能会覆盖其空间。但这是一个假设(很可能是公平的),在某些情况下可能导致不确定的行为

但为了更简洁,因为您有两个实体要分配,所以需要两个分配

collection = malloc( sizeof *collection );
collection->items = malloc( sizeof(collection->items[0]) * 1000 );
Run Code Online (Sandbox Code Playgroud)

稍后都将被释放。

在这种情况下,结构应为

typedef struct myarray {
  int len;
  void **;
} MYARRAY
Run Code Online (Sandbox Code Playgroud)

由于MYARRAY它本身很小,因此您也可以静态声明它

static MYARRAY collection;
Run Code Online (Sandbox Code Playgroud)
  1. 进口

#import已弃用,请#include改用。


Jer*_*ner 5

One problem is here:

void mypush(void* state) {
   DATA data = { state };
   int pos = collection.len++;
   collection.items[pos] = &data;
}
Run Code Online (Sandbox Code Playgroud)

Note that the last line of this function stores a pointer to the local variable data into your items array. But as soon as the mypush() function returns, that local variable is destroyed, which means that the pointer you stored into the array is no longer valid! (it is now a dangling pointer) Most likely your segmentation fault occurs when you later on try to read from that now-invalid pointer (which invokes undefined behavior, and in this case, a crash)

为避免这种情况,只需直接存储state变量,而根本不涉及局部data变量。您可以根据需要将其他指针类型void *强制转换为(和从)其他指针类型(只要您谨慎确保强制转换与指针指向的数据的实际类型相匹配-使用空指针,编译器就不会告诉您是否要投放到不合适的类型!)