紧凑的指针表示法与双打

时间:2010-01-15 06:51:57

标签: c++ pointers

快速提问。当你访问一个字符数组时,我知道你可以设置指向数组中第一个元素的指针,并使用while看看并执行类似

的操作
while (*ptr != '\0') {
   do something
}

现在有一个double或int等价物吗?

#define ARRAY_SIZE 10
double someArray[ARRAY_SIZE] = {0};
double *ptr = someArray;
// then not sure what to do here?  I guess I am looking for an equivalent of the above while loop, but don't want to just do:
for (int i = 0; i < ARRAY_SIZE); *ptr++) 
cout << *ptr;

谢谢!

7 个答案:

答案 0 :(得分:4)

如果我理解正确,你想迭代数组并在* ptr有特定值时停止。这并不总是可行的。对于字符数组(字符串),一个常见的约定是使字符串为“空终止”;也就是说,它最后会有一个0字节('\ 0')。你可以将这样的标记添加到int或双值数组中(如果你可以挑出一个不会被使用的“特殊”值),但它不是一种普遍适用的技术。

顺便说一句,你的for循环可能不是你想要的:

for (int i = 0; i < ARRAY_SIZE); *ptr++)

如果要迭代数组,则需要递增指针(ptr ++),而不是指向它的值(* ptr ++)。

答案 1 :(得分:1)

目前尚不清楚您在寻找什么。

第一个循环的结构(“字符数组”版本)取决于您不使用抽象字符数组,而是使用驻留在 C-string 中的 C-string 那个数组。 C字符串是由零字符终止的字符序列(在数组中)。这个零字符就是终止你的第一个循环。

使用显式指针处理double数组没有问题。你是在第二个例子中自己做的(尽管有错误)。如果您的double数组明确包含以double值终止的0.0值序列,则您的double周期甚至可能与您的char周期完全相同。

double *ptr = someArray;
while (*ptr != 0.0)
  cout << *ptr++;    

但通常情况并非如此。零终止的double数组不是在实践中经常使用的东西。

通常你会知道数组的大小,这意味着迭代的组织方式会有所不同。有很多不同的方法可以做到这一点,所以这主要取决于个人品味。以下是几个例子

double *ptr;
for (unsigned n = ARRAY_SIZE, ptr = someArray; n > 0; --n, ++ptr)
  cout << *ptr;

for (double *ptr = someArray, *ptr_end = ptr + ARRAY_SIZE; ptr != ptr_end; ++ptr)
  cout << *ptr;

double *ptr;
for (unsigned i = 0, ptr = someArray; i < ARRAY_SIZE; ++i, ++ptr)
  cout << *ptr;

等等。

答案 2 :(得分:1)

在C中,字符串根据定义以'\ 0'字符终止。具有特殊值(在本例中为'\ 0'字符)表示序列的结尾有时称为使用标记。在其他数据结构中使用标记并不罕见,但它绝不是普遍的。

如果你有一组以已知值终止的整数或双精度数,那么你可以使用一种技术来遍历该序列,类似于通过字符串中的字符行走直到你点击'\ 0'。问题在于你必须确保它与哨兵正确终止的顺序,你的哨兵不能是你在序列中可能找到的值作为实际的数据。

常见的哨兵值是:

  • 0(零)
  • -1
  • MAX_INT

但您可以使用对您的应用程序有意义的任何内容。假设您的应用程序仅处理非负双打,您可以使用负值作为哨兵:

double *ptr = someArray;

while (*ptr >= 0.0) {
    cout << *ptr;
    ++ptr;
}

使用标记终止数组的好处是可以很容易地处理可变长度数组。

缺点是:

  • 您有一个无法合法用作数据的值(如果您决定必须处理负值,则上述示例是一个大问题)
  • 你必须承担阵列正确终止的痛苦
  • 在为数组分配空间时,你必须确保不要忘记为sentinel分配一个元素。
  • 你必须走数组以确定它有多大

使用sentinel的替代方法是通过仅处理编译时已知的特定大小的数组或者将数组大小作为参数传递(或将其包装在结构中)来承载数组的大小。数组或指向数组的指针。)

答案 3 :(得分:1)

(这里没有什么新内容在其他答案中没有说,但我会尝试简洁地提供解释和示例而不会失去清晰度。)

循环查看'\0'的char数组是有效的,因为C样式的字符串有一个int,double和大多数其他类型没有的约定:null-termination。 (该'\0'字符被称为“null”或“NUL”,但很少“NULL”以避免与该名称的宏混淆。)

由于int和double数组没有此约定,因此必须使用其他内容。以下是最简单的替代方案:

// pass arrays with their size
void ex1(double const* data, int size) {
  for (int n = 0; n < size; ++n) {
    use(data[n]);
  }
}

// use a container class which has a size() method
void ex2(vector<double> const& v) {
  for (int n = 0; n < v.size(); ++n) {
    use(data[n]);
  }
  // or:
  for (vector<double>::const_iterator i = v.begin(); i != v.end(); ++i) {
    use(*i);
  }
  // or, sometimes a slight tweak:
  for (vector<double>::const_iterator i = v.begin(), end = v.end();
       i != end; ++i
  ) {
    use(*i);
  }
}

// pass an iterator range, once you are familiar with iterators
void ex3(double const* begin, int const* end) {
  for (double const* i = begin; i != end; ++i) {
    use(*i);
  }
}

以及如何使用它们:

void ex4() {
  double data[] = {3, 5, 42}; // if you don't want to specify the size, then use
  int length = len(data);  // this special len function to get the array length
  // len defined below

  ex1(data, length);   // easy to pass with size now
  ex2(vector<double>(data, data + length));   // easy to create a container too
  ex3(data, data + length);
    // notice the container creation takes a similar iterator range

  double buncha_zeros[42] = {}; // or even if you specify the length
  length = len(buncha_zeros); // you still don't have to repeat yourself
}

template<class T, int N>
N len(T (&)[N]) {
  return N;
}
// note: this exists in boost in a better, more general form as boost::size

将“double”替换为“int”或几乎任何其他类型,此处的所有内容都相同。

答案 4 :(得分:0)

除非可以保证数组中不会出现特定的值(例如null终止的“0”字节)串)。

答案 5 :(得分:0)

是的,双精度数组的指针符号完全相同。

以下是您的计划的更正版本:

#include <iostream>

#define ARRAY_SIZE 10

int main(void) {
    double someArray[ARRAY_SIZE] = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9};
    double *ptr = someArray;

    for (int i = 0; i < ARRAY_SIZE; i++, *ptr++) 
        std::cout << *ptr;
}

该程序的输出是:

0123456789

答案 6 :(得分:0)

对于C风格的字符串,惯例是字符串以0结尾。这意味着您不能在C风格的字符串中使用0

如果您有一个不需要的double值,可以将其存储在数组的末尾,然后检查它。例如,您可以使用0或NaN(非数字)。了解如何在CC++中使用NaN。如果您确实使用非NaN号作为标记,则在比较浮点数之前应阅读The pitfalls of verifying floating-point computations

当然,由于您使用的是C ++,并且您不想记住数组的大小,因此您应该考虑使用std::vector<double>