我是C的新手,如果这是非常基本的话,请提前抱歉。这与家庭作业有关。
我有几个辅助函数,每个都改变一个给定变量的值(主要是二进制操作),即:
void helper1(unsigned short *x, arg1, arg2) --> x = &some_new_x
main函数调用其他参数 arg3,arg4,arg5 。 x 应该首先从0(16位0)开始,然后由辅助函数修改,并且在所有修改之后,最终应该由 mainFunction 返回
我在哪里声明初始 x 以及如何/在哪里分配/释放内存?如果我在 mainFunc 中声明它,则每次调用助手时它都会重置为0。如果我释放并重新分配辅助函数内的内存,即使我释放并分配了所有内容,我仍然得到“指针被释放未分配”错误。全局变量也没有。
我会说我并不完全理解内存分配,所以我假设我的问题是这个,但我完全有可能只是不明白如何在更基本的层面上更改C中的变量值。 ..
答案 0 :(得分:1)
变量x
将在执行它的块执行时存在,即使在帮助程序执行期间也是如此,并且给指向帮助程序的指针允许它们更改其值。如果我理解你的问题,你就不需要动态内存分配。以下代码从mainFunction
返回4:
void plus_one(unsigned short* x)
{
*x = *x + 1;
}
unsigned short mainFunction(void)
{
unsigned short x = 0;
plus_one(&x);
plus_one(&x);
plus_one(&x);
plus_one(&x);
return x;
}
答案 1 :(得分:1)
根据你的描述,我建议将main函数中的x声明为局部变量(从堆栈中分配),然后通过引用将其传递给辅助函数,并按值从主函数返回。
int main()
{
int x; //local variable
helper(&x); //passed by reference
return x; //returned by value
}
在帮助程序中,您可以通过取消引用并分配所需的任何值来修改变量:
void helper(int * x)
{
*x = ...; //change value of x
}
另一种方法是声明一个指向x(从堆中分配)的指针,将其传递给你的帮助函数,并在你不再使用它时释放它。但是这条路线需要更仔细的考虑并且容易出错。
答案 2 :(得分:0)
函数接收其对本地范围变量的输入的值的副本。因此,辅助函数不可能更改它所调用的值,只能更改其本地副本。
void f(int n)
{
n = 2;
}
int main()
{
int n = 1;
f(n);
return 0;
}
尽管名称相同,但n
中的f
是f
调用的本地名称。因此n
中的main
永远不会改变。
解决这个问题的方法是通过指针传递:
int f(int *n)
{
*n = 2;
}
int main()
{
int n = 1;
f(&n);
// now we also see n == 2.
return 0;
}
请注意,n
中的f
同样是本地的,因此如果我们更改n
中的指针f
,则对main
无效的观点。如果我们想更改n
中的地址main
,我们必须传递指针的地址。
void f1(int* nPtr)
{
nPtr = malloc(sizeof int);
*nPtr = 2;
}
void f2(int** nPtr)
{
// since nPtr is a pointer-to-a-pointer,
// we have to dereference it once to
// reach the "pointer-to-int"
// typeof nPtr = (int*)*
// typeof *nPtr = int*
*nPtr = malloc(sizeof int);
// deref once to get to int*, deref that for int
**nPtr = 2;
}
int main()
{
int *nPtr = NULL;
f1(nPtr); // passes 'NULL' to param 1 of f1.
// after the call, our 'nPtr' is still NULL
f2(&nPtr); // passes the *address* of our nPtr variable
// nPtr here should no-longer be null.
return 0;
}
----编辑:关于分配的所有权----
指针的所有权是一堆乱七八糟的蠕虫;标准C库有一个函数strdup
,它返回一个指向字符串副本的指针。程序员需要了解指针是用malloc
分配的,并且应该通过调用free
将其释放给内存管理器。
随着指向的事情变得更加复杂,这种方法变得更加繁重。例如,如果您获得目录结构,则可能需要了解每个条目都是您负责释放的已分配指针。
dir = getDirectory(dirName);
for (i = 0; i < numEntries; i++) {
printf("%d: %s\n", i, dir[i]->de_name);
free(dir[i]);
}
free(dir);
如果这是一个文件操作,如果库没有提供close
函数并让你自己拆除文件描述符,你会感到有些惊讶。
许多现代图书馆倾向于承担其资源的责任,并提供匹配的获取和发布功能,例如:打开和关闭MySQL连接:
// allocate a MySQL descriptor and initialize it.
MYSQL* conn = mysql_init(NULL);
DoStuffWithDBConnection(conn);
// release everything.
mysql_close(conn);
LibEvent有,例如</ p>
bufferevent_new();
分配事件缓冲区和
bufferevent_free();
发布它,即使它实际上做的只是malloc()和free(),但是通过让你调用这些函数,它们提供了一个明确定义且清晰的API,它承担了解这些事情的责任。
这是C ++中被称为“RAII”概念的基础