使用指针跨越INTEGER数组中的所有元素

时间:2011-02-20 10:13:35

标签: c++ c arrays pointers

有没有办法使用指针跨越整数数组中的所有元素(类似于使用指针跨越字符串元素)。我知道整数数组不是NULL终止所以当我尝试使用指针交叉数组时它会溢出。所以我添加了NULL作为数组的最后一个元素,它运行得很好。

int array[7]={1,12,41,45,58,68,NULL};
int *i;
for(i=array;*i;i++)
    printf("%d ",*i);

但是,如果数组中的一个元素为0,那将表现为NULL。是否有任何其他方法可以实现指针跨越整数数组中的所有元素?

8 个答案:

答案 0 :(得分:5)

一般情况下,除非你选择的 sentinel值不属于有效的数据范围。例如,有效范围可能是正数,因此您可以使用负数(如-1)作为指示数组末尾的标记值。这是C风格的字符串如何工作;使用NULL终止符是因为它超出了可以表示字符的有效整数范围。

但是,通常最好以某种方式将数组指针与另一个指示数组大小的变量配对,或者将另一个指针指向数组的一端(

)。

在您的具体情况下,您可以执行以下操作:

// Note that you don't have to specify the length of the array.
int array[] = {1,12,41,45,58,68};
// Let the compiler count the number of elements for us.
int arraySize = sizeof(array)/sizeof(int);
// or int arraySize = sizeof(array)/sizeof(array[0]);

int main()
{
    int* i;
    for(i = array; i != array + arraySize; i++)
        printf("%d ",*i);
}

你也可以这样做:

int arrayBegin[] = {1,12,41,45,58,68};
int* arrayEnd = arrayBegin + sizeof(arrayBegin)/sizeof(arrayBegin[0]);

int main()
{
    int* i;
    for(i = arrayBegin; i != arrayEnd; i++)
        printf("%d ",*i);
}

但是只给出一个指针,你不知道它指向的数组有多长。实际上,你甚至无法判断指针是指向数组还是单个对象! (至少不便携。)

如果你有必须接受数组的函数,要么你的函数需要:

  • 指针指针所指向的数组的大小
  • 两个指针,其中一个指向数组的第一个元素,另一个指向数组的一个接一个结尾。

答案 1 :(得分:2)

您可以使用指针遍历C样式字符串的原因是256个不同的字符值,其中一个特别保留为“这是字符串的结尾”。因此,C风格的字符串不能在其中的任何位置存储空字符。

当您尝试对整数数组使用类似的技巧时,您会注意到同样的问题。如果你想能够在某个时刻停止,你将不得不选择一些整数并保留它意味着“这不是一个整数;它实际上是整数序列的结束。”所以不,除非你愿意选择一些通常不会出现在字符串中的值,否则没有通用的方法来获取整数数组并用特殊值标定结尾。

C ++选择了与C不同的方法来描述序列。 C ++样式范围(如您在vectorstringlist中找到的)存储两个迭代器{{1},而不是使用某种null终止符存储元素。 }和begin(),表示第一个元素和结束后的第一个元素。您可以通过编写

来迭代这些范围
end()

这种方法比定义范围的C字符串方法更灵活,因为它不依赖于范围内任何值的特定属性。如果你想迭代一系列整数值,我建议选择使用这样的东西。它更明确地表示范围的界限,并且不会遇到某些值无法存储在范围内的奇怪问题。

答案 2 :(得分:2)

我想提供一些额外的建议:永远不要在数组中使用某种类型的sentinel / termination值来确定它们的界限。这使您的程序容易出错,并且通常是导致安全问题的原因。您应始终存储数组的长度,以将所有操作限制为其边界,并针对该值进行测试。

在C ++中,您拥有STL及其容器。

在C中你最终会使用像

这样的结构
typedef struct t_int_array 
{
    size_t length;
    int data[1]; /* note the 1 (one) */
} int_array;

和一组像这样的操作函数

int_array * new_int_array(size_t length)
{
    int_array * array;
    /* we're allocating the size of basic t_int_array 
      (which already contains space for one int)
      and additional space for length-1 ints */
    array = malloc( sizeof(t_int_array) + sizeof(int) * (length - 1) );
    if(!array)
        return 0;
    array->length = length;
    return array;
}

int_array * concat_int_arrays(int_array const * const A, int_array const * const B);
int_array * int_array_push_back(int_array const * const A, int const value);
/* and so on */

此方法将使编译器以某种方式对齐t_int_array结构,这对于目标体系结构(也使用malloc分配)是最佳的,并且只需为数据数组元素的元素大小分配更多空间将保持这种方式。

答案 3 :(得分:0)

除了通常建议你应该使用STL之外,你可以找到这样的固定数组的长度:

int array[6]={1,12,41,45,58,68};
for (int i = 0; i < sizeof(array) / sizeof(array[0]); ++i)
{ }

如果使用模板化函数,则可以隐式得出这样的长度:

template<size_t len> void func(int (&array)[len])
{
    for (int i = 0; i < len; ++i) { }
}

int array[6]={1,12,41,45,58,68};
func(array);

如果0是正常整数数组中可能出现的值,则可以指定其他值:

const int END_OF_ARRAY = 0x80000000;
int array[8]={0,1,12,41,45,58,68,END_OF_ARRAY};
for (int i = 0; array[i] != END_OF_ARRAY; ++i)
{ }

如果每个值都有可能,或者其他任何方法都不起作用(例如,动态数组),则必须分别管理长度。这是允许嵌入空字符工作的字符串(例如BSTR)。

答案 4 :(得分:0)

在您的示例中,您使用(或者说滥用)NULL宏作为sentinel value;这是C字符串中NUL('\0')字符的函数,但在C字符串的情况下,除了作为终端(或sentinel)值之外,NUL不是有效字符。

NULL宏旨在表示无效指针而不是整数值(尽管在C ++中隐式或显式地转换为int时,其值保证为零,而在C中这是也几乎总是如此)。在这种情况下,如果要使用零作为标记值,​​则应使用文字零而不是NULL。问题当然是如果在这个应用程序中零是一个有效的数据值,它就不适合用作哨兵。

例如,以下内容可能适合:

static const int SENTINEL_VALUE = -1 ;
int array[7] = { 1, 12, 41, 45, 58, 68, SENTINEL_VALUE } ;
int* i ;

for( i = array; *i != SENTINEL_VALUE; i++ )
{
    printf( "%d ", *i ) ;
}

如果所有整数值都是有效的数据值,那么您将无法使用sentinel值,并且必须使用容器类(知道其长度)或迭代已知的数组长度(来自sizeof())。

答案 5 :(得分:0)

只是为了先前的答案而迂腐和扩展:在处理C中的整数数组时,依赖于数组本身的标记值几乎是罕见的。没有(1)理智的程序员这样做。为什么不?因为根据定义,整数可以将任何值保持在预定义的负/正限制内,或者(对于现在非常见的32位整数)0到0xffffff。通过窃取其中一个可能的哨兵值来重新定义“整数”的概念并不是一件好事。

相反,一个始终(1)必须(1)依赖于控制数组中整数的最新计数。假设我们要编写一个C函数 返回一个指向第一个数组成员的int指针,该数组成员的值大于函数的参数,如果没有这样的成员,则返回NULL(所有代码都未经测试):`


int my_int_array[10];  // maximum of 10 integers in my_int_array[], which must be static
int member_count = 0;  // varies from 0 to 10, always holds number of ints in my_int_array[]
int *
first_greater_than ( int val ) {
  int i;
  int *p;
  for ( i = 0, p = my_int_array; i < member_count; ++i, ++p ) {
    if ( *p > val ) {
      return p;
    }
  }
  return NULL;
}

更好的是将i的值限制为永远不会计算过去 my_int_array []的最后一个成员,即它永远不会超过9,而p永远不会指向my_int_array [10] ]及以后:


int my_int_array[10];  // maximum of 10 integers in my_int_array[], which must be static
int member_count = 0;  // varies from 0 to 10, always holds number of ints in my_int_array[]
int *
first_greater_than ( int val ) {
#define MAX_COUNT sizeof(my_int_array)/sizeof(int)
  int  i;
  int* p;
  for ( i = 0, p = my_int_array; i < member_count && i < MAX_COUNT; ++i, ++p ) {
    if ( *p > val ) {
      return p;
    }
  }
  return NULL;
}
HTH和我道歉,如果这只是太基本了。

- 皮特

  1. 不严格,但现在相信

答案 6 :(得分:0)

在ANSI C中,它比以前的解决方案更容易和更短:

int array[]={1,12,41,45,58,68}, *i=array;
size_t numelems = sizeof array/sizeof*array;
while( numelems-- )
    printf("%d ",*i++);

答案 7 :(得分:0)

另一种方法是管理指向int的指针数组:

#include <stdlib.h>
#include <stdio.h>

#define MAX_ELEMENTS 10

int main() {
 int * array[MAX_ELEMENTS];
 int ** i;
 int k;

 // initialize MAX_ELEMENTS,1 matrix
 for (k=0;k<MAX_ELEMENTS;k++) {
  array[k] = malloc(sizeof(int*));
  // last element of array will be NULL pointer
  if (k==MAX_ELEMENTS-1)
    array[k] = NULL;
  else
    array[k][0] = k;
 }

 // now loop until you get NULL pointer
 for (i=array;*i;i++) {
  printf("value %i\n",**i);
 }

 // free memory
 for (k=0;k<MAX_ELEMENTS;k++) {
  free(array[k]);
 }

 return 0;
}

这样循环条件完全独立于整数值。但是......为此,你必须使用2D数组(矩阵)而不是普通的1D数组。希望有所帮助。