简体   繁体   English

C ++中使用指针的数组中的元素数

[英]The number of elements in an array using pointers in C++

So while studying for my exams I was trying to do a practice problem for pointers. 因此,在为考试学习时,我试图为指针做一个练习题。

In the following code I'm trying to display the number of elements before the first occurrence of 0. 在以下代码中,我尝试显示首次出现0之前的元素数。

There is only one part that i didn't understand please see the 6th last line. 只有一部分我听不懂,请参阅第六行。

#include <iostream>

using namespace std;

int main()
{
    int A[10];
    for (int i = 0; i < 10; i++){
        cout << "Please enter number " << i + 1 << " in the array: ";
        cin >> A[i];
    }
    int *Aptr = A;
    while(*Aptr !=0){
        cout << *Aptr << "";
        Aptr++;
    }
    cout << "\nThere are " << (Aptr - A)  //Here is what i don't understand.
    << " numbers before the first occurrence of 0." << endl;

    system("pause");
    return 0;
}

So why exactly is (Aptr - A) giving me the number of elements instead of a memory location, and why is this even doable since Aptr is a pointer and A is an array? 那么,为什么(Aptr-A)确切地给了我元素个数而不是内存位置,又为什么因为Aptr是一个指针而A是一个数组,这甚至可行呢?

Can someone explain to me in detail? 有人可以详细向我解释吗?

When used in an expression, like Aptr - A , the name of an array A will be implicitly converted to a pointer (equal to &A[0] ). 当在表达式(如Aptr - A ,数组A的名称将隐式转换为指针(等于&A[0] )。

Then the compiler is faced with subtracting two pointers of the same type (both of type int * in your case). 然后,编译器将要减去两个相同类型的指针(在您的情况下均为int *类型)。 That is specified as giving a value of type std::ptrdiff_t , which is, in turn "a signed integral type able to represent the result of subtracting two pointers". 这被指定为给出类型为std::ptrdiff_t的值,该值又是“一个有符号的整数类型,能够表示减去两个指针的结果”。

Pointer arithmetic, when subtracting two pointers of type int (ie two int * s) gives the number of int s between the two pointers (assuming they are in the same object, which is true in this case, since Aptr points at an element of the array A ). 指针算术,当减去两个类型为int指针(即两个int * s)时,将得出两个指针之间的int数(假设它们在同一个对象中,在这种情况下是正确的,因为Aptr指向的元素为数组A )。

Practically, if Aptr is equal to &A[i] , the subtraction Aptr - &A[0] gives a std::ptrdiff_t equal to i . 实际上,如果Aptr等于&A[i] ,则减法Aptr - &A[0]给出等于istd::ptrdiff_t

Note: there is another problem in your code, as since the first ( for ) loop reads 10 values, while the second while loop keeps incrementing Aptr until it points at an int with value 0 . 注意:您的代码中还有另一个问题,因为第一个( for )循环读取10值,而第二个while循环保持Aptr递增,直到它指向值为0int为止。 If the user enters any zero values, the second loop will stop when it finds the first (even if the user enters non-zero elements after that). 如果用户输入任何零值,则第二个循环在找到第一个循环时将停止(即使用户在此之后输入非零元素)。 If the user enters no values equal to 0 , then the while loop has undefined behaviour, since Aptr will keep walking through memory past the end of A until it happens to find memory that compares (as an int ) equal to 0 . 如果用户没有输入任何等于0值,则while循环具有未定义的行为,因为Aptr将继续遍历A末尾的内存,直到碰巧找到比较(等于int )等于0内存。

First of all, name of array A is associated to address of (pointer at) the first item in the array. 首先,数组A名称与数组中第一项的地址(指针指向)相关联。

So why exactly is (Aptr - A) giving me the number of elements? 那么,为什么(Aptr-A)确实给了我元素个数呢?

Because according to rules address arithmetic subtraction operation (also + , and similar) is performed based on the data type. 因为根据规则,地址算术减法运算(还有+和类似的运算)是基于数据类型执行的。

I mean, that compiler operating with int* makes ++ , -- , addition, subtraction an integer, etc. adds addresses needed for shifting to next/previous item. 我的意思是,使用int*进行操作的编译器使++-- ,加法,减法成为整数等,从而添加了移至下一个/上一个项目所需的地址。

If you really want to see how many bytes are located between addresses, just convert addresses to int before making subtraction: 如果您真的想查看地址之间有多少字节,只需在进行减法之前将地址转换为int

 cout << endl << "Address difference is " << int(Aptr) - int(A) << endl;

You can try that with different data types as follows: 您可以尝试使用以下不同的数据类型:

#include <iostream>
#include <iomanip>
using namespace std;

int main()
{
    int A[5];
    short B[5];
    unsigned char C[5];
    cout << "Array (data type) | Syze of array | Size of item | Item distanse | Bytes distance" << endl;
    cout << "A (int)           :" << setw(10) 
                            << sizeof(A) << setw(15)
                            << sizeof(A[0]) << setw(15) 
                            << &A[4] - A << setw(15) 
                            << int(&A[4]) - int(A) << endl;
    cout << "B (short)         :" << setw(10) 
                            << sizeof(B) << setw(15)
                            << sizeof(B[0]) << setw(15) 
                            << &B[4] - B << setw(15) 
                            << int(&B[4]) - int(B) << endl;
    cout << "C (un.char)       :" << setw(10)
                            << sizeof(C) << setw(15)
                            << sizeof(C[0]) << setw(15)
                            << &C[4] - C << setw(15)
                            << int(&C[4]) - int(C) << endl;

    system("pause");
    return 0;
}

UPDATE 更新

To be better prepared for your exam, consider the following example with pointers: 为了更好地准备考试,请考虑以下带有指针的示例:

#include <iostream>
using namespace std;

int main()
{
    int A[5] = {0}; // all items now are 0
    int * P = A + 2; // the same as P = &A[2];
    *P = 33; // writing to item A[2];
    cout << A[2] << endl; // just to check in usual way
    cout << *(A + 2) << endl; // using A as a pointer
    cout << *(2 + A) << endl; // almost the same to previous
    cout << 2[A] << endl; // quite strange, but it works
    cout << 0[P] << endl; // and this is the same
    return 0;
}

You must understand that 0[P] means for compiler *(0 + P) , as well as 2[A] means - *(2 + A) , but you should not write in your program in such style (exceptions are only cases when you want to confuse a reader). 您必须了解0[P]表示编译器*(0 + P) ,以及2[A]表示- *(2 + A) ,但您不应以这种方式编写程序(例外情况是例外当您想使读者感到困惑时)。

And one more important thing - difference between array and pointer - are shown in the following example: 下面的示例显示了更重要的事情-数组和指针之间的区别-

    int A[] = {1, 2, 3, 4, 5};
    int *P = A;
    cout << "A = " << A << endl;
    cout << "P = " << P << endl;
    cout << "size of A = " << sizeof(A) << endl;
    cout << "size of P = " << sizeof(P) << endl;

even if the addresses (vaules A and P) are equal, compiler works with array ( A ) in a different way than with pointer: sizeof(A) means memory allocated for whole array (5 items of sizeof(int) each), but sizeof(P) means memory allocated for data type int * (pointer to int). 即使地址(值A和P)相等,编译器对数组( A )的处理方式也与指针不同: sizeof(A)表示为整个数组分配内存sizeof(int)每个5项sizeof(int) ),但是sizeof(P)表示分配给数据类型int * (指向int的指针sizeof(P)内存。 So, sizeof(P) depends only on compiler and OS platform (eg pointer can be 32-bit or 64-bit), but sizeof(A) depends on size of item ( int may be not 32 bits) and NUMBER OF ITEMS in the array. 因此, sizeof(P)仅取决于编译器和OS平台(例如,指针可以是32位或64位),但是sizeof(A)取决于项目的大小( int可能不是32位)和数组。

And you can "go to the next item" with pointer: 您可以使用指针“转到下一个项目”:

  P++;
  cout << *P << endl;

but you are not able to do: 但您无法执行以下操作:

  A++;

because A is not variable of pointer type (it is just similar in sense of "address of the first item"), and compiler will say you something like: 因为A不是指针类型的变量(就“第一项的地址”而言,它是相似的),并且编译器会说:

error : '++' needs l-value 错误:“ ++”需要左值

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM