我正在尝试学习C而我正在尝试编写一个基本的堆栈数据结构,但我似乎无法获得基本malloc/ free正确.
这是我一直在使用的代码(我只是在这里发布一小部分来说明一个特定的问题,而不是总代码,但错误消息是通过运行此示例代码生成的valgrind)
#include <stdio.h>
#include <stdlib.h>
typedef struct Entry {
struct Entry *previous;
int value;
} Entry;
void destroyEntry(Entry entry);
int main(int argc, char *argv[])
{
Entry* apple;
apple = malloc(sizeof(Entry));
destroyEntry(*(apple));
return 0;
}
void destroyEntry(Entry entry)
{
Entry *entry_ptr = &entry;
free(entry_ptr);
return;
}
Run Code Online (Sandbox Code Playgroud)
当我运行它valgrind时--leak-check=full --track-origins=yes,我收到以下错误:
==20674== Invalid free() / delete / delete[] / realloc()
==20674== at 0x4028E58: free (vg_replace_malloc.c:427)
==20674== by 0x80485B2: destroyEntry (testing.c:53)
==20674== by 0x8048477: …Run Code Online (Sandbox Code Playgroud) 在我大学的C编程课程中,教授及其后来的书在引用C中的指针时使用了术语调用或通过引用传递.
我的教授称之为"参考函数调用"的一个例子:
int sum(int *a, int *b);
Run Code Online (Sandbox Code Playgroud)
我的教授称之为"价值函数呼叫"的一个例子:
int sum(int a, int b);
Run Code Online (Sandbox Code Playgroud)
我读过 C不支持通过引用调用.根据我的理解,指针通过值传递.
基本上,说指针是C通过引用传递的方式是不正确的吗?说你不能通过C中的引用传递但是可以使用指针替代它会更正确吗?
2015年11月11日更新
从我的问题起源的方式来看,我认为术语的争论已经产生,实际上我看到了两个具体的区别.
在阅读了@Haris的更新答案之后,为什么这不是那么黑白,这是有道理的.
这些都是一样的:
int foo(bar* p) {
return p->someInt();
}
Run Code Online (Sandbox Code Playgroud)
和
int foo(bar& r) {
return r.someInt();
}
Run Code Online (Sandbox Code Playgroud)
忽略空指针潜力.这两个函数在功能上是否相同,无论它们someInt()是虚拟的还是传递给它们bar的子类bar?
这会切片吗:
bar& ref = *ptr_to_bar;
Run Code Online (Sandbox Code Playgroud) 令人惊讶的简单/愚蠢/基本问题,但我不知道:假设我想让我的函数的用户返回一个C字符串,其长度我不知道在函数的开头.我可以在开始时仅在长度上放置上限,并且根据处理,尺寸可能缩小.
问题是,分配足够的堆空间(上限)然后在处理期间终止字符串是否有任何问题?即如果我在分配的内存中间插入'\ 0',(a.)是否free()仍能正常工作,并且(b.)'\ 0'之后的空格变得无关紧要?一旦'\ 0'被添加,内存是否会被返回,或者它是否位于占用空间直到free()被调用?将这个悬空空间留在那里通常是不好的编程风格,为了节省一些前期编程时间,在调用malloc之前计算必要的空间?
为了给出这个上下文,假设我想删除连续的重复项,如下所示:
输入"你好oOOOo !!" - >输出"Helo oOo!"
...以及下面的一些代码显示了我如何预先计算操作产生的大小,有效地执行两次处理以使堆大小正确.
char* RemoveChains(const char* str)
{
if (str == NULL) {
return NULL;
}
if (strlen(str) == 0) {
char* outstr = (char*)malloc(1);
*outstr = '\0';
return outstr;
}
const char* original = str; // for reuse
char prev = *str++; // [prev][str][str+1]...
unsigned int outlen = 1; // first char auto-counted
// Determine length necessary by mimicking processing
while (*str) {
if (*str != …Run Code Online (Sandbox Code Playgroud) 我已经在多个上下文中阅读过“胖指针”一词,但是我不确定它的确切含义以及何时在Rust中使用它。该指针似乎是普通指针的两倍,但我不明白为什么。它也似乎与特征对象有关。
这两个声明之间有什么区别吗?
int x[10];
Run Code Online (Sandbox Code Playgroud)
与
int* x = new int[10];
Run Code Online (Sandbox Code Playgroud)
我认为前一个声明(如后一个声明)是一个指针声明,两个变量都可以相同.这是否意味着它们本质上是一样的?
Javascript通过引用传递对象.这很有道理.但是一旦你开始操纵这些物体,一切都会以一种看起来不直观的方式发挥作用.让我举一个例子:
var a, b;
a = {}
b = a;
a['one'] = {};
console.log( JSON.stringify(a) );
// outputs: {"one":{}}
console.log( JSON.stringify(b) );
// outputs: {"one":{}}
Run Code Online (Sandbox Code Playgroud)
这一切都很好,因为现在b有一个指针,a所以预计分配东西a也会影响b.
但是如果我这样做:
a = a['one'];
console.log( JSON.stringify(a) );
// outputs: {}
console.log( JSON.stringify(b) );
// outputs: {"one":{}}
Run Code Online (Sandbox Code Playgroud)
这对我来说很惊讶.我期望a,并b仍然是相同的(并且是{}因为a['one']原先设置为{}和a设置为a['one']).
但事实并非如此.似乎a失去了b对它被赋予新内容的时间的引用,但b保留了a在a失去引用之前设置的值b.
但是如果我这样做:
a['two'] …Run Code Online (Sandbox Code Playgroud) 我在这里看到了一种奇怪的程序.
int main()
{
int s[]={3,6,9,12,18};
int* p=+s;
}
Run Code Online (Sandbox Code Playgroud)
上面的程序在GCC和Clang编译器上进行了测试,并在两个编译器上都运行良好.
我很想知道,int* p=+s;做了什么?
数组是否已s衰减为指针类型?
这是允许通过引用传递数组?
void foo(double& *bar)
Run Code Online (Sandbox Code Playgroud)
似乎我的编译器说没有.为什么?通过引用传递数组的正确方法是什么?还是一个解决方法?我有一个数组参数,我的方法应该修改,然后我应该检索.或者,我可以使这个数组成为一个类成员,它工作正常,但它对我的代码的其他部分有很多缺点(我想避免).
感谢致敬.
我在最近的一次采访中被问到有关C++结构字段对齐的问题,并且理论上C和C++在结构打包中遵循相同的策略.
Hovewer,这是错误的假设.采访者说,一般来说,C和C++以不同的方式包装结构,我们永远不应该期待相反的结果.恕我直言,这是一个奇怪的声明.pack "C"在C++中没有用于双语C/C++头文件的结构限定符.
因此在实践中,它可能意味着您无法在C++中创建结构并将其传递给C库,因为通常它的字段将以不同的方式对齐并具有不同的偏移量.但实际上,大多数程序员都非常依赖这种互操作性,直到他们将一个指向C POD结构的指针转换为对这个结构的C++包装器的引用,并使用了一些辅助方法.你能澄清一下这个问题吗?