内存分配和更改值

时间:2014-02-10 00:11:01

标签: c memory-management

我是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中的变量值。 ..

3 个答案:

答案 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中的ff调用的本地名称。因此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”概念的基础