是否可以定义没有temp / aux变量的指针? (或者这会是不好的C编码吗?)

时间:2019-02-14 14:49:50

标签: c pointers

我试图了解C指针。作为背景,我习惯于在C#Python3中进行编码。

我知道可以使用指针来保存变量的地址(写type* ptr = &var;之类的东西),并且递增指针等同于递增该对象类型{{1}的对象数组的索引}。但是我不明白的是,您是否可以使用type(例如type的指针和引用对象而没有引用已经定义的变量。

我想不出一种方法,大多数C / C ++指针示例似乎都使用它们来引用变量。因此,可能是我要问的是不可能的和/或不好的编码实践。如果是这样,则有助于理解原因。

例如,为了澄清我的困惑, if 如果不使用预定义的硬编码变量就无法使用指针,为什么要使用指针而不是直接使用基本对象或数组?对象?

下面有一小段代码正式描述了我的问题。

非常感谢您的任何建议!

int

5 个答案:

答案 0 :(得分:6)

是的,您可以使用动态内存(也称为“堆”)分配:

#include <stdlib.h>

int * const integer = malloc(sizeof *integer);
if (integer != NULL)
{
  *integer = 4711;
  printf("forty seven eleven is %d\n", *integer);
  free(integer);
  // At this point we can no longer use the pointer, the memory is not ours any more.
}

这要求C库从操作系统分配一些内存并返回指向它的指针。分配sizeof *integer个字节可以使分配恰好适合整数,然后我们可以使用*integer取消对指针的引用,这几乎就像直接引用整数一样。

答案 1 :(得分:1)

在C语言中,函数的参数始终按值传递,因此在函数中更改参数值不会反映在调用者中。但是,您可以使用指针来模拟按引用传递。例如:

void clear(int *x)
{
    *x = 0;
}

int main()
{
    int a = 4;
    printf("a=%d\n", a);   //  prints 4
    clear(&a);
    printf("a=%d\n", a);   //  prints 0
    return 0;
}

您还可以使用指针指向动态分配的内存:

int *getarray(int size)
{
    int *array = malloc(size * sizeof *array);
    if (!array) {
        perror("malloc failed"); 
        exit(1);
    }
    return array;
}

这些只是几个例子。

答案 2 :(得分:1)

在C语言中使用指针有很多充分的理由,其中之一是,您只能在C语言中通过 value 传递-您不能通过引用传递。因此,将指针传递到现有变量可以节省将其复制到堆栈的开销。作为一个例子,让我们假设这个非常大的结构:

struct very_large_structure {
    uint8_t kilobyte[1024];
}

现在假设需要使用此结构的函数:

bool has_zero(struct very_large_structure structure) {
    for (int i = 0; i < sizeof(structure); i++) {
        if (0 == structure.kilobyte[i]) {
            return true;
        }
    }

    return false;
}

因此要调用此函数,您需要将整个结构复制到堆栈中,尤其是在嵌入式平台上,其中C被广泛使用,这是不可接受的要求。

如果您将通过指针传递结构,则仅将指针本身(通常是32位数字)复制到堆栈中:

bool has_zero(struct very_large_structure *structure) {
    for (int i = 0; i < sizeof(*structure); i++) {
        if (0 == structure->kilobyte[i]) {
            return true;
        }
    }

    return false;
}

这绝不是唯一,最重要的指针用法,但它清楚地说明了为什么指针在C语言中很重要的原因。

答案 3 :(得分:1)

  

但是我不明白的是,您是否可以使用指针和类型(例如int)的引用对象而无需引用已经定义的变量。

是的,有两种情况是可能的。

第一种情况是动态内存分配。您可以使用malloccallocrealloc函数从动态内存池(“堆”)分配内存:

int *ptr = malloc( sizeof *ptr ); // allocate enough memory for a single `int` object
*ptr = some_value; 

第二种情况是,您为I / O通道或端口或某物指定了一个固定的,定义明确的地址:

char *port = (char *) OxDEADBEEF;

尽管这在嵌入式系统中比普通的应用程序编程更为常见。

编辑

关于第二种情况,chapter and verse

6.3.2.3指针

...
5整数可以转换为任何指针类型。除先前指定外, 结果是实现定义的,可能未正确对齐,可能未指向 引用类型的实体,并且可能是陷阱表示。 67)

67)用于将指针转换为整数或将整数转换为指针的映射函数旨在 与执行环境的寻址结构一致。

答案 4 :(得分:0)

最常见的原因:因为您希望在不传递内容的情况下修改内容。

类比:
如果您想对客厅进行粉刷,则不想将房子放在卡车拖车上,将其移到油漆工上,让他做,然后拖回去。这将是昂贵且费时的。如果您的房子太宽了,无法在街上拖拉,卡车可能会撞车。您宁愿告诉画家您住的住址,让他去那里做这项工作。

用C表示,如果您有一个大的struct或类似名称,则需要一个函数在不复制该结构的情况下访问该结构,将一个副本传递给该函数,然后复制回修改后的内容回到原始变量。

// BAD CODE, DONT DO THIS
typedef struct { ... } really_big;
really_big rb;
rb = do_stuff(rb);

...    

rb do_stuff (really_big thing) // pass by value, return by value
{
  thing->something = ...;
  ...
  return thing;  
}

这将复制称为rb的{​​{1}}。它被放置在堆栈上,浪费了大量内存,并且不必要地增加了所使用的堆栈空间,从而增加了堆栈溢出的可能性。并且将内容从thing复制到rb会花费很多执行时间。然后,当它返回时,您又制作了一个副本,从thing回到thing

通过传递指向该结构的指针,不会进行任何复制,但是最终结果是完全相同的:

rb