在C++中什么时候应该使用指针?

39 浏览
0 Comments

在C++中什么时候应该使用指针?

我知道这是一个非常基础的问题,但是在用高级语言编写了几个项目后,我刚刚开始学习一些基本的C++编程。\n基本上我有三个问题:\n

    \n

  1. 为什么要使用指针而不是普通变量?
  2. \n

  3. 什么时候和在哪里应该使用指针?
  4. \n

  5. 如何在数组中使用指针?
  6. \n

0
0 Comments

当在C++中应该使用指针?

指针允许您从多个位置引用同一内存空间。这意味着您可以在一个位置更新内存,并且可以从程序中的另一个位置看到更改。通过能够共享数据结构中的组件,您还可以节省空间。

您应该在需要获取和传递内存中特定位置的地址的任何地方使用指针。您还可以使用指针来导航数组:

数组是一块连续的内存块,已分配了特定类型。数组的名称包含数组的起始位置的值。当您添加1时,这将带您到第二个位置。这使您可以编写循环,增加滑动数组的指针,而不需要显式计数器来访问数组。

以下是C语言的一个示例:

char hello[] = "hello";
char *p = hello;
while (*p)
{
    *p += 1; // 将字符增加一
    p += 1; // 移动到下一个位置
}
printf(hello);

打印结果为`ifmmp`,因为它获取每个字符的值并将其增加了一。

“因为它获取每个字符的值并将其增加了一”,是以ASCII表示还是怎么样?

`p=0;`会重置指针吗?

0
0 Comments

在C++中使用指针的一个原因是可以在被调用的函数中修改变量或对象。C++中使用引用而不是指针是一个更好的实践。尽管引用本质上是指针,但C++在某种程度上隐藏了这一事实,并使其看起来像是按值传递。这使得可以轻松更改调用函数接收值的方式,而无需修改传递的语义。

考虑以下示例:

使用引用:

public void doSomething()
{
    int i = 10;
    doSomethingElse(i);  // 通过引用传递i,因为doSomethingElse()以引用接收它,
                         // 但语法使得看起来像是按值传递i
}
public void doSomethingElse(int& i)  // 以引用接收i
{
    cout << i << endl;
}

使用指针:

public void doSomething()
{
    int i = 10;
    doSomethingElse(&i);
}
public void doSomethingElse(int* i)
{
    cout << *i << endl;
}

可能需要提到引用比指针更安全,因为不能传递空引用。

是的,这可能是使用引用的最大优势。感谢指出这一点。没有故意的双关意思 🙂

你确实可以传递空引用。只是传递空指针不像传递空引用那么容易。

同意。如果你认为不能传递空引用,那么你是错的。传递悬空引用比传递空引用更容易,但最终你都可以做到。引用并不是保护工程师不踩坑的万能药。参见实际演示

这不是使用指针的原因,这是使用引用的原因。而且,实际上,这不是一个很好的原因,我们应该避免使用非const引用参数,除非真的有必要(通常情况下并没有必要)。

0
0 Comments

当你在C++中应该使用指针?

简短的答案是:不要。;-) 指针应该在你无法使用其他任何东西的情况下使用。这可能是因为缺乏适当的功能,缺少数据类型,或者出于性能考虑。以下是更详细的解释...

何时何地应该使用指针?

简短的答案是:在你无法使用其他任何东西的情况下。在C语言中,你没有任何支持复杂数据类型(如字符串)的功能。也没有办法将变量“按引用”传递给函数。这就是你必须使用指针的地方。此外,你可以用它们指向几乎任何东西,如链表、结构体的成员等等。但我们不在这里详细介绍这些。

如何使用数组指针?

需要付出一些努力并引起许多混淆。;-) 如果我们讨论的是诸如int和char之类的简单数据类型,那么数组和指针之间几乎没有区别。

这些声明非常相似(但不完全相同 - 例如,sizeof将返回不同的值):

char* a = "Hello";
char a[] = "Hello";

你可以这样访问数组中的任何元素:

printf("Second char is: %c", a[1]);

索引为1,因为数组从第0个元素开始。 🙂

或者你也可以这样做:

printf("Second char is: %c", *(a+1));

需要使用指针运算符(*),因为我们告诉printf我们想要打印一个字符。如果没有*,则会打印内存地址本身的字符表示。现在我们使用字符本身。如果我们使用的是%s而不是%c,我们将要求printf打印指针'a'指向的内存地址加一(在上面的示例中),并且我们不必在前面放*:

printf("Second char is: %s", (a+1)); /* 错误 */

但这不仅会打印第二个字符,而是打印直到找到空字符(\0)的所有下一个内存地址中的所有字符。这就是事情开始变得危险的地方。如果你不小心尝试打印int类型的变量而不是char指针与%s格式化程序,会怎么样?

char* a = "Hello";
int b = 120;
printf("Second char is: %s", b);

这将打印在内存地址120上找到的任何内容,并继续打印,直到找到空字符为止。执行此printf语句是错误和非法的,但它可能仍然会工作,因为在许多环境中,指针实际上是int类型的。想象一下,如果你使用sprintf(),并将这个太长的“char数组”分配给另一个只分配了一定限定空间的变量,你可能最终会在内存中覆盖其他内容,导致你的程序崩溃(如果你幸运的话)。

哦,如果在声明时没有为char数组/指针分配字符串值,那么在给它赋值之前,你必须为其分配足够的内存空间。使用malloc、calloc或类似的函数。这是因为你只声明了数组/指针中的一个元素/一个单独的内存地址。所以这里有一些例子:

char* x;
/* 分配6个字节的内存给我,并将x指向其中的第一个字节。 */
x = (char*) malloc(6);
x[0] = 'H';
x[1] = 'e';
x[2] = 'l';
x[3] = 'l';
x[4] = 'o';
x[5] = '\0';
printf("String \"%s\" at address: %d\n", x, x);
/* 删除内存的分配(保留)。 */
/* char指针x仍然指向内存中的这个地址! */
free(x);
/* 与malloc相同,但这里分配的空间填充了null字符!*/
x = (char *) calloc(6, sizeof(x));
x[0] = 'H';
x[1] = 'e';
x[2] = 'l';
x[3] = 'l';
x[4] = 'o';
x[5] = '\0';
printf("String \"%s\" at address: %d\n", x, x);
/* 然后再次删除分配... */
free(x);
/* 我们也可以在声明时设置大小 */
char xx[6];
xx[0] = 'H';
xx[1] = 'e';
xx[2] = 'l';
xx[3] = 'l';
xx[4] = 'o';
xx[5] = '\0';
printf("String \"%s\" at address: %d\n", xx, xx);

请注意,即使在执行了free()释放了分配的内存之后,你仍然可以使用变量x,但你不知道其中存储了什么。还要注意,由于第二次内存分配是否在与第一次相同的空间中执行没有保证,所以两个printf()可能会给出不同的地址。

你的例子中有一个错误。它使用%c而不是%s,所以没有错误;它只是打印了小写字母x。此外,你随后声称指针是int类型是错误的,对于一个没有使用过指针的C程序员来说,这是非常糟糕的建议。

... %c已更改为%s

-1 你开始得很好,但第一个例子是错误的。不,它们不一样。在第一种情况下,a是一个指针,在第二种情况下,a是一个数组。我之前有提到吗?它们不一样!自己检查一下:比较sizeof(a),尝试为数组分配新的地址。它不会起作用。

“执行此printf语句是错误或非法的。” 这是完全错误的。在许多实现中,这个printf语句会导致未定义行为。指针实际上不是int类型,它们只是指针(仅此而已)。

-1,你在这里的许多事实都是错误的,我直接说你不值得得到这么多赞和被接受的回答状态。

comp.lang.c FAQ的第6部分很好地解释了C语言中数组和指针之间的关系。这个答案并没有解释清楚。

“不要” -1。可选(空)参数。从函数中“可选”返回的值。

-1 C++中的多态性需要使用指针。

实际上并不需要。void do_something(Base& x) { x.virtual_method(); } int main() { Derived d; DoSomething(d); }在不使用指针的情况下调用虚函数。然而,指针使共享、复制和几乎所有其他操作变得容易。

:boost不是C++的一部分。

对不起,问题上的C++标签让我困惑了。

:它是一个可选的第三方库。如果他们决定将boost::optional纳入核心语言,你的反驳意见可能会变得有效。

实际上,在你的例子中,指针确实涉及其中。'&'只是语法糖,让它看起来像你没有使用指针。

我在isocpp上读到,它将成为C++14的一部分。

实际上,没有地方写道引用是如何使用指针实现的。

除非你找到了一个说法是这样实现的,否则我仍然坚持我说的。这只是它必须的工作方式。使用引用时,你引用的是可能属于不同堆栈级别的值。并且修改它实际上会修改原始位置上的值。这正是指针的工作方式。此外,这个页面说在调用函数时值不会被复制。指针必须被涉及。

C++11标准从未指定引用应该如何实现。这是编译器的选择,你不应该依赖它。大多数编译器使用指针来实现引用与使用引用时指针确实有关无关。

好吧。可能存在一个效率低下的编译器,它在调用函数时复制参数值,然后在之后将其复制回来。不管怎样,关键是你需要以一种形式或另一种形式进行间接引用,以便在C++中利用子类型多态性。传递引用是一种间接引用的形式。

-1:“这些声明都是相同的char* a = "Hello"; char a[] = "Hello";” - 不,不是。他们不是相同的。

这个回答在2008年是不错的,但是现在应该更新一下,使用std::array和字符串视图。

文章整理如下:

在C++中,什么时候应该使用指针?

简短的答案是:尽量不要使用指针。指针应该在没有其他选择的情况下使用,因为它们容易引发错误和导致程序崩溃。指针的使用主要是为了解决C语言中缺乏复杂数据类型和无法按引用传递变量给函数的问题。

指针的使用有时是必要的,例如在处理字符串或链表等数据结构时。然而,指针的使用也容易引起错误。例如,如果错误地将指向整型变量的指针传递给printf函数的%s格式化程序,将导致程序读取错误的内存地址并可能导致崩溃。因此,在使用指针时要特别小心,并确保正确地使用指针运算符(*)和格式化程序。

使用指针与数组的关系也需要注意。虽然数组名可以被视为指向数组第一个元素的指针,但它们并不完全相同。数组和指针之间的主要区别在于sizeof运算符返回的结果不同,并且不能将新的地址分配给数组名。因此,在处理数组时要注意这些区别,并确保正确使用数组和指针。

总之,指针在C++中应该谨慎使用。在大多数情况下,应该尽量使用更安全和更易于理解的方法来处理数据。只有在没有其他选择的情况下,或者为了性能优化等特殊需求,才应该使用指针。

0