简体   繁体   English

为什么我们需要把*用于指针

[英]Why do we need to put * for pointer

I was reading about pointers when suddenly I thought that if pointer is nothing but a variable that stores memory address of a variable so every integer should work as a pointer. 当我突然想到指针只是一个存储变量的内存地址的变量时,我正在读指针,所以每个整数都应该作为指针。 Then I created a small program, it gave warning but it somehow worked. 然后我创建了一个小程序,它发出警告,但它以某种方式工作。

int main()
{
    int i,j;
    i=3;
    j=&i;
    printf("%d\n%d\n%d",i,j,&i);
    return 0;
}

Output was 输出是

3
1606416600
1606416600

So, why to put an extra * if normal int does the work? 那么,为什么要添加额外的*如果正常的int工作呢?

Another question is about the output to following program 另一个问题是关于以下计划的输出

int main()
{
    int a[] = {1,2,3,4,5,6,7};
    int *i,*j;
    i=&a[1];
    j=&a[5];
    printf("%d\n%d\n%d",j,i,j-i);
    return 0;
}

Output : 输出:

1606416580
1606416564
4

Why is ji = 4 and not 16? 为什么ji = 4而不是16?

Why do we need to put * for pointer 为什么我们需要把*用于指针

Because the language specification says so. 因为语言规范是这样说的。

So, why to put an extra * if normal int does the work? 那么,为什么要添加额外的*如果正常的int工作呢?

Because "normal" int does not do the work. 因为“普通” int不起作用。 Nor does an "abnormal" int . 也没有“异常” int

Pointers are a separate type. 指针是一种单独的类型。 No wonder the human brain can easily imagine them as indices into a huuuuuge array of bytes called "the memory", but that's not necessarily what computers and compilers do. 难怪人类大脑很容易将它们想象成一个称为“记忆”的huuuuuge字节数组的索引,但这并不一定是计算机和编译器所做的。 The C standard says that conversion between pointers and int is an implementation-defined operation. C标准表示指针和int之间的转换是一个实现定义的操作。

You can store a pointer without loss of data if you use the built-int types intptr_t or uintptr_t , though -- but neither of those is guaranteed to be an int (or an unsigned int , for that matter). 如果使用built-int类型intptr_tuintptr_t ,则可以存储指针而不会丢失数据 - 但是这些都不能保证是int (或者unsigned int ,就此而言)。


As to your second question: because that's how pointer arithmetic is defined. 关于你的第二个问题:因为那是指针运算的定义方式。 And it's defined like so because that's how it's logical and intuitive. 并且它的定义是这样的,因为它是如何合乎逻辑和直观的。 If p2 = p1 + 4 , then p2 - p1 is 4 and not 16. 如果p2 = p1 + 4 ,则p2 - p1为4而不是16。

See this question for more information about pointer arithmetic. 有关指针算法的更多信息, 请参阅此问题


Oh, and technically, your first program has undefined behavior because printing pointers is done using the %p conversion specifier, but you used %d which is for int . 哦,从技术上讲,你的第一个程序有未定义的行为,因为打印指针是使用%p转换说明符完成的,但是你使用了%d来表示int Your first program would be correct like this: 你的第一个程序是这样的:

printf("%d\n%d\n%p", i, j, (void *)&i);

(also notice the cast to void * -- this is one of the few cases where a cast to void * is required, else you have UB again.) (还要注意演员表void * - 这是少数需要演员void *情况之一否则你再次获得UB。)

It is down to having type safety. 这取决于具有类型安全性。 Ie using one thing when it should not be used to do something other. 即使用一件事,它不应该被用来做其他事情。

See http://en.wikipedia.org/wiki/Type_safety http://en.wikipedia.org/wiki/Type_safety

(Adding to the already good answers of @H2CO3 and @EdHeal.) (增加了@ H2CO3和@EdHeal已经很好的答案。)

At Assembly level you could treat an address as an int and do any sort of dirty tricks with them, but C is a much higher level language than Assembly. 在程序集级别,您可以将地址视为int并使用它们执行任何类型的脏技巧,但C语言是比汇编语言高得多的语言。 What does it mean "high level" in the context of programming languages? 在编程语言环境中它意味着什么是“高级”? It is short for "high level of abstraction", which means that it is a language that is closer to how humans write and think . 它是“高级抽象”的缩写,这意味着它是一种更接近人类写作和思考方式的语言

In a sense, it's all about "abstractions". 从某种意义上说,这都是关于“抽象”的。 Think of a car, for example. 比如想一辆车。 You don't need to know all the gory engineering details just to drive it safely. 您不需要知道所有血腥工程细节,只是为了安全驾驶它。 You view a car as a "much higher level abstraction" compared to what a mechanical engineer has to. 与机械工程师相比,您将汽车视为“更高层次的抽象”。 Why is this useful? 为什么这有用? Because your brain has the freedom to concentrate on driving you home without being involved in a car accident, instead of being forced to think of, say, how many revolutions per minutes every cogwheel in the engine has to do. 因为你的大脑可以自由地集中精力驾驶你而不会卷入车祸,而不是被迫想到,例如,发动机中的每个齿轮每分钟转数需要多少转。

The metaphor is valid also for programming languages: abstractions are useful because they spare you the effort of thinking of every tiny detail of the underlying implementation. 这个比喻对于编程语言也是有效的:抽象是有用的,因为它们可以让你不遗余力地思考底层实现的每个微小细节。 A pointer is an abstraction (although not a very high level one, compared to what you find in more modern languages): it is the archetypal model of an indirect reference to something. 指针一种抽象(虽然不是一个非常高级的指针,与你在更现代的语言中找到的相比):它是间接引用某事物的原型模型。 Under the hood it may be implemented as an address, as a handle or as a whole different thing, but its semantics is described (and mandated) by the standard. 在引擎盖下,它可以实现为地址,句柄或整体不同的东西,但它的语义由标准描述(和强制)。 Thus you are saved from many problems that are the nightmare of Assembly programmers, especially when switching platform or architecture: pointers also help you make portable programs. 因此,您可以避免许多问题,这些问题是汇编程序员的噩梦,特别是在切换平台或架构时:指针还可以帮助您制作可移植程序。

Pointers are not always simply integers. 指针并不总是简单的整数。 They are integers on the vast majority of current implementations, but they can be more complex. 它们是绝大多数当前实现的整数,但它们可能更复杂。 An example is implementations that were done for 8086 processors. 一个例子是为8086处理器完成的实现。 A simple integer pointer wwould have been limited to only accessing a 64k address space. 一个简单的整数指针仅限于访问64k地址空间。 To cope with this C compilers would implement different memory models. 为了应对这个C编译器,将实现不同的内存模型。 A tiny memory model would use simple integers for pointers and would be limited to a max of 64k for the program code, data and stack combined. 一个微小的内存模型将使用简单的整数作为指针,并且对于程序代码,数据和堆栈组合将限制为最大64k。 A small memory model would also use simple integers but split the code & data into one segment and the stack into another. 小内存模型也会使用简单的整数,但将代码和数据拆分为一个段,将堆栈拆分为另一个段。 This allowed for 128k programs. 这允许128k节目。 Other memory models would use pointers that consisted of a segment:offset pair of integers which allowed for larger program sizes. 其他内存模型将使用由段组成的指针:偏移整数对,允许更大的程序大小。 The bottom line is that a pointer abstracts out the the concept of a memory location from its implementation. 底线是指针从其实现中抽象出内存位置的概念。

Pointers are indeed commonly implemented as memory addresses, and they can in that case be thought of as integers. 指针确实通常被实现为内存地址,在这种情况下它们可以被认为是整数。 As you experienced, it is even possible to convert between the two, although you must be careful that the size of the integer type is as big as the size of a memory address (the pointer size). 正如您所经历的那样,甚至可以在两者之间进行转换,但必须注意整数类型的大小与内存地址的大小(指针大小)一样大。

The reason that a * is used, has to do with type safety. 使用*的原因与类型安全有关。 Something of type int* is 'an address of an integer', whereas somthing of type float* is 'the address of a float'. int*类型的东西是'整数的地址',而float*类型的东西是' float*的地址'。 If you were to treat those in the same way, you would lose information about the type of the value at the address. 如果您以相同的方式对待它们,您将丢失有关地址值的类型的信息。

As for your second question, this is called pointer arithmetic . 至于你的第二个问题,这叫做指针算术 Address differences will be reported as multiplier of the element size, and not in actual bytes. 地址差异将报告为元素大小的乘数,而不是实际字节。 Because sizeof(int) is 4 in your case, and there is a difference of 16 bytes between the addresses, the result of the operation is 16/4 = 4. The result is the number of elements difference , which is 5 - 1 = 4. 因为sizeof(int)在你的情况下是4,并且地址之间有16个字节的差异,操作的结果是16/4 = 4.结果是元素数量的差异 ,即5 - 1 = 4。

Edit: although H2CO3's answer is technically correct, I think this explanation is more intuitive. 编辑:虽然H2CO3的答案在技术上是正确的,但我认为这种解释更直观。

Pointers and integers have a different type because they are two different things, even though pointers are implemented as integers on many architectures. 指针和整数具有不同的类型,因为它们是两个不同的东西,即使指针在许多体系结构上实现为整数。 But consider for example the x86_64 architecture, there are implementations where integers are 64 bits wide and pointers are 32 bits wide. 但是考虑一下x86_64架构,有些实现的整数是64位宽,指针是32位宽。

Apart from the address representation and type "safety" issue, the specific pointer type (as opposed to a single general pointer type) is required for pointer arithmetic and assignment. 除了地址表示和类型“安全”问题之外,指针算术和赋值还需要特定的指针类型(而不是单个通用指针类型)。 (Those are not used in your example.) (在您的示例中未使用这些。)

Pointer arithmetics: 指针算术:

int intArr[2] = {1, 2};
int* pInt0 = &intArr[0];     // points to intArr[0]
int* pInt1 = pInt0 + 1;      // points to intArr[1]

char* pChar0 = pInt0;       // points to the first  byte of intArr[0]
char* pChar1 = pChar0 + 1;  // points to the second byte of intArr[0]

(see 6.3.2.3/7) (见6.3.2.3/7)

Assignment through a pointer: 通过指针分配:

int obj = 42;
unsigned char buf[sizeof(obj)];
for(unsigned i = 0; i < sizeof(obj); ++i) {  // like memcpy
    unsigned char* source = i + (unsigned char*)&obj;
    unsigned char* dest = i + buf;
    *dest = *source;    // copies one byte
}

int obj2 = 0;
int* pObj2 = &obj2;

*pObj2 = obj;           // copies sizeof(int) bytes

(see 6.2.6.1/4) (见6.2.6.1/4)

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

相关问题 为什么我们需要“this pointer adjustor thunk”? - Why do we need "this pointer adjustor thunk"? 为什么我们需要不同的指针数据类型? - Why do we need different datatype for pointer? 为什么我们需要一个指针 - Why do we need a pointer here 为什么我们需要超类的指针指向子类的对象? - Why do we need a pointer of superclass to point to a object of a subclass? 为什么我们需要使用std :: vector :: pointer来访问元素? - Why do we need to use std::vector::pointer to access elements? strtok_s()为什么我们需要指针的地址? - strtok_s() Why do we need address of a pointer? 为什么我们需要在 C++ 中检查空指针,而在 Java 中不需要? - Why do we need to check null pointer in C++, but not in Java? 为什么我们需要传递 const 共享指针作为引用? - Why do we need to pass const shared pointer as reference? 当我们通过引用传递时,为什么在调用函数时我们放置一个变量而不是地址(指针)? - When we pass by reference, why do we put a variable instead of address(pointer), when calling the function? 如果我们可以实例化一个对象并访问该类的成员,为什么我们需要一个指向类的指针? - Why do we need a pointer to a class if we can instantiate an object of it and access members of the class?
 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM