我想我已经把它归结为最基本的情况:
int main(int argc, char ** argv) {
int * arr;
foo(arr);
printf("car[3]=%d\n",arr[3]);
free (arr);
return 1;
}
void foo(int * arr) {
arr = (int*) malloc( sizeof(int)*25 );
arr[3] = 69;
}
Run Code Online (Sandbox Code Playgroud)
输出是这样的:
> ./a.out
car[3]=-1869558540
a.out(4100) malloc: *** error for object 0x8fe01037: Non-aligned pointer
being freed
*** set a breakpoint in malloc_error_break to debug
>
Run Code Online (Sandbox Code Playgroud)
如果有人能够阐明我的理解失败的地方,我们将不胜感激.
我使用函数指针的结构来实现不同后端的接口.签名非常不同,但返回值几乎都是void,void*或int.
struct my_interface {
void (*func_a)(int i);
void *(*func_b)(const char *bla);
...
int (*func_z)(char foo);
};
Run Code Online (Sandbox Code Playgroud)
但是后端不需要支持每个接口函数的功能.所以我有两种可能性,第一种选择是在每次调用之前检查指针是否为NULL.我不太喜欢这样,因为可读性和因为我担心性能影响(但我没有测量它).另一种选择是具有虚函数,对于极少数情况,接口函数不存在.
因此,我需要为每个签名都使用一个虚函数,我想知道是否有可能只有一个用于不同的返回值.并将其转换为给定的签名.
#include <stdio.h>
int nothing(void) {return 0;}
typedef int (*cb_t)(int);
int main(void)
{
cb_t func;
int i;
func = (cb_t) nothing;
i = func(1);
printf("%d\n", i);
return 0;
}
Run Code Online (Sandbox Code Playgroud)
我用gcc测试了这段代码,它确实有效.但它是否理智?或者它可以破坏堆栈还是会导致其他问题?
编辑:感谢所有答案,经过一番深入阅读后,我现在学到了很多关于调用约定的知识.并且现在可以更好地理解引擎盖下发生的事情.
在阅读了一些教程后,我得出的结论是,应该总是使用指针来表示对象.但是我在阅读一些QT教程(http://zetcode.com/gui/qt4/painting/)时也看到了一些例外,其中QPaint对象是在堆栈上创建的.所以现在我很困惑.我什么时候应该使用指针?
我有一个main具有char 的函数,我试图将指针传递给char函数并将其更改为A,B但它似乎并没有改变它.这里显示的例子只是代码的当前状态我尝试了许多不同的变体,因此可能存在其他错误,只是简单地抓住吸管.
int main()
{
char result = 'A';
setChar(&result);
printf("%C", result);
}
void setChar(char* charToChange)
{
charToChange = "B";
}
Run Code Online (Sandbox Code Playgroud) 使用realloc时内存是否自动释放?或者是否有必要免费使用realloc?以下哪项是正确的?
//Situation A
ptr1 = realloc(ptr1, 3 * sizeof(int));
//Situation B
ptr1 = realloc(ptr2, 3 * sizeof(int));
free(ptr1);
ptr1 = ptr2;
Run Code Online (Sandbox Code Playgroud) 每个C程序员都可以使用这个众所周知的宏来确定数组中元素的数量:
#define NUM_ELEMS(a) (sizeof(a)/sizeof 0[a])
Run Code Online (Sandbox Code Playgroud)
这是一个典型的用例:
int numbers[] = {2, 3, 5, 7, 11, 13, 17, 19};
printf("%lu\n", NUM_ELEMS(numbers)); // 8, as expected
Run Code Online (Sandbox Code Playgroud)
但是,没有什么能阻止程序员意外地传递指针而不是数组:
int * pointer = numbers;
printf("%lu\n", NUM_ELEMS(pointer));
Run Code Online (Sandbox Code Playgroud)
在我的系统上,这打印2,因为显然,指针是整数的两倍.我想过如何防止程序员错误地传递指针,我找到了一个解决方案:
#define NUM_ELEMS(a) (assert((void*)&(a) == (void*)(a)), (sizeof(a)/sizeof 0[a]))
Run Code Online (Sandbox Code Playgroud)
这是有效的,因为指向数组的指针与指向其第一个元素的指针具有相同的值.如果改为传递指针,指针将与指向自身的指针进行比较,这几乎总是假的.(唯一的例外是递归的void指针,也就是指向自身的void指针.我可以忍受它.)
意外地传递指针而不是数组现在在运行时触发错误:
Assertion `(void*)&(pointer) == (void*)(pointer)' failed.
Run Code Online (Sandbox Code Playgroud)
太好了!现在我有几个问题:
我的用法是assert逗号表达式的左操作数有效标准C吗?也就是说,标准是否允许我assert用作表达式?对不起,如果这是一个愚蠢的问题:)
可以在编译时以某种方式完成检查吗?
我的C编译器认为这int b[NUM_ELEMS(a)];是一个VLA.有没有办法说服他呢?
我是第一个想到这个吗?如果是这样,我可以期待在天堂等待多少处女?:)
所以,我总是知道在C/C++中传递的数组"对象"只包含数组中第一个对象的地址.
指向数组"对象"的指针和它包含的值如何相同?
有人可能会向我指出更多信息,也许是关于汇编中的所有信息.
为什么在c或c ++中不支持添加两个指针.
当我做,
int *ptr,*ptr1;
int sum = ptr + ptr1;
Run Code Online (Sandbox Code Playgroud)
C或C++会抛出错误.虽然它支持,
int diff = ptr - ptr1;
Run Code Online (Sandbox Code Playgroud) 我不确定下面的陈述是否由标准C明确定义
*p1++ += 2;
Run Code Online (Sandbox Code Playgroud)
或其他类似声明:
*E1++ <operator>= E2
Run Code Online (Sandbox Code Playgroud)
从标准C关于后增量:
postfix ++运算符的结果是操作数的值.获得结果后,操作数的值递增.(即,将相应类型的值1添加到其中.)有关约束,类型和转换以及操作对指针的影响的信息,请参阅加法运算符和复合赋值的讨论.更新操作数的存储值的副作用应发生在前一个和下一个序列点之间.
关于coumpund-assignment:
E1 op = E2形式的复合赋值与简单赋值表达式E1 = E1 op(E2)的不同之处仅在于左值E1仅被评估一次.
这是我前一个问题的切线跟进.匹配bool vs const void*overload的函数的地址.回答者解释说:
[C++ 11]标准没有定义从"指向函数的指针"到"指向"的任何标准转换
void.没有东西可以提供引用,但我能做的最接近的是C++ 11 4.10/2 [conv.ptr]:
类型为"指向cv的 指针"的prvalue
T,其中T是对象类型,可以转换为类型为"指向cv的 指针"的prvaluevoid.一个"指针转换的结果CVT"发送给"指针CVvoid"指向其中类型的对象的存储位置的起始T驻留,仿佛对象是类型T的最派生对象(1.8)(即,而不是基类子对象).空指针值将转换为目标类型的空指针值.(强调我的)
假设func是声明void func();,如果你进行C风格的演员表,即(void*) func演员表会成功.static_cast<void*>(func)但是无效,但reinterpret_cast<void*>(func)会成功.但是,您无法将后续转换的指针转换回其原始类型.例如,
精细:
int main() {
int* i;
void* s = static_cast<void*>(i);
i = static_cast<int*>(s);
s = reinterpret_cast<void*>(i);
i = reinterpret_cast<int*>(s);
}
Run Code Online (Sandbox Code Playgroud)
不好:
void func() { }
int main() { …Run Code Online (Sandbox Code Playgroud)