Elementary C language - pointer

Posted by roldahayes on Sat, 26 Feb 2022 15:41:28 +0100

catalogue

I What is the pointer

II Pointer and pointer type

3. Field pointer

4. Pointer operation

5. Pointer and array

6. Secondary pointer

7. Pointer array

I What is the pointer

Understand pointer

1. Pointer is the number of the smallest unit in memory, that is, the address
2. The pointer in spoken English usually refers to the pointer variable, which is used to store the memory address (i.e. store the pointer)
Conclusion: pointer is the address. In colloquial language, pointer usually refers to pointer variable.

Pointer variable

1. We can take out the initial memory address of the variable through & (take address operator) and store the address in a variable, which is a pointer variable.
2. Pointer variable, which is used to store the variable of address. (the values stored in the pointer are treated as addresses)

How big is a small unit? (1 byte)

Pointer addressing

For a 32-bit machine, it is assumed that there are 32 address lines. It is assumed that each address line generates high level (high voltage) and low level (low voltage) during addressing, which is (1 or 0)
Then the address generated by 32 address lines will be:
00000000 00000000 00000000 00000000
00000000 00000000 00000000 00000001 ...
11111111 11111111 11111111 11111111
There are 32 addresses to the power of 2.
Each address identifies a byte, so we can address 4G of free memory (2^32Byte == 2^32/1024KB == 2^32/1024/1024MB==2^32/1024/1024/1024GB == 4GB)
Here we understand:
1. On a 32-bit machine, the address is a binary sequence of 32 zeros or 1s, and the address must be stored in a space of 4 bytes, so the size of a pointer variable should be 4 bytes.
2. On a 64 bit machine, if there are 64 address lines, the size of a pointer variable is 8 bytes to store an address.
Summary: pointer variables are used to store addresses, which uniquely mark an address space. The size of the pointer is 4 bytes on 32-bit platforms and 8 bytes on 64 bit platforms.

II Pointer and pointer type

1. The definition method of pointer is: type +*
2. Meaning of pointer type
① The pointer type determines how far the pointer can go in one step, that is, the step size
② The pointer type determines the permission of pointer dereference

Example:

#include <stdio.h>
//Demonstration example
int main()
{
 int n = 10;
 char *pc = (char*)&n;//Take out the address of n and store it in the pointer variable pc of char type
 int *pi = &n;//Take out the address of n and store it in the pointer variable pi of type int
 
 printf("%p\n", &n);
 printf("%p\n", pc);
 printf("%p\n", pc+1);
 printf("%p\n", pi);
 printf("%p\n", pi+1);
 return  0;
}

Program running results

The running results of the program are shown in the figure above:
We found that the printed address of pc+1 is 1 more than that of pc, that is, 1 more byte, that is, one more char type. Compared with pi, pi+1 has 4 more bytes, that is, an int type. The extra part is the same size as their pointer type, so it can be concluded that the pointer type determines how far the pointer can go, that is, the step length

Example 2:

 
//Demonstration example
#include <stdio.h>
int main()
{
 int n = 0x11223344;
 char *pc = (char *)&n;//Store n in char type pointer variable
 int *pi = &n;//Store n in the pointer variable pi of type int
 *pc = 0;   //Dereference
 *pi = 0;   //Focus on observing their changes in memory during debugging.
 return 0;
}

The memory changes are shown in the figure above. We obviously observed that when * pc=0, only one byte of memory is 0, while * pi=0 actually makes four bytes of memory 0.
So it is concluded that the pointer type determines the permission of pointer dereference.
For an integer array, use the integer pointer for the operation of one element per element. If you want the operation of one byte per byte, use the char pointer

3. Field pointer

Concept: Wild pointer means that the position pointed by the pointer is unknowable (random, incorrect and unrestricted), just like a wild dog

Origin of wild pointer

1. Pointer not initialized

int main()
{
//Here p is called the wild pointer
   int *p;//p is a local pointer variable. If the local variable is not initialized, it defaults to a random value!
   *p = 10;//Illegal access to memory
   return 0;
}

2. Pointer cross-border access

#include <stdio.h>
int main()
{
    int arr[10] = {0};
    int *p = arr;
    int i = 0;
    for(i=0; i<=11; i++)
   {
        //Since arr has only 10 elements, arr[11] is out of the range of the array. When the range pointed to by the pointer exceeds the range of array arr, p is the wild pointer
        *(p++) = i;
   }
    return 0;
}
3. The space pointed by the pointer is released
int *test()
{
    int a=10;
    return &a;
}
int main()
{
    int *p=test();//(illegal access to memory), because after the function is called, a is destroyed, but the address is still retained, so it is illegal.
    *p=20;
    return 0;
}

How to avoid wild pointer

1. Initialize pointer
2. Be careful that the pointer is out of range
3. Place NULL in time after the pointer points to the space
4. Check the validity of the pointer before use
5. Avoid returning the address of local variables

Take chestnuts for example:

#include <stdio.h>
int main()
{ 
    //When you don't know what address p should initialize at present, it is directly initialized to a null pointer
    int *p=NULL;
    //Clearly know the initialization value
    int a=10;
    int *p=&a;
    //The C language itself does not check for data cross-border behavior
    if(p!=NULL)//Check whether the pointer is empty
        *p=0;
}

4. Pointer operation

Pointer + - integer

The addition and subtraction of pointer variables is to add and subtract the stored address.

#define N_VALUES 5
float values[N_VALUES];
float *vp;
for (vp = &values[0]; vp < &values[N_VALUES];)//Pointer relational operation, that is, comparing the size of the address.
{
     *vp++ = 0;//Pointer + - integer;
}

Pointer pointer

1. Pointer - the pointer gets the number of elements between two pointers
2. The premise of pointer subtraction is that two pointers point to the same space

Example 1:

int main()
{
    int arr[10]={1,2,3,4,5,6,7,8,9,10};
    printf("%d\n",&arr[9]-&arr[0]);//The result is 9, including arr[0], but excluding arr[9]
    char c[5];
    printf("%d\n",&arr[9]-&c[0]);//err, because it's not in the same space
    return 0;
}

Example 2: method of finding string length

//Counter
int my_strlen1(char* str)
{
    int count = 0;
    while (*str != '\0')
    {
        count++;
        str++;
    }
    return count;
}
//recursion
int my_strlen2(char* pa)
{
    if (*pa == '\0')
    {
        return 0;
    }
    else
        return 1 + my_strlen2(pa + 1);
}
//Pointer pointer. As long as you get the address of the first element and the address of \ 0, you can get the number of elements between the two pointers.
int my_strlen3(char* pa)
{
    char* start = pa;
    while (*pa != '\0')
    {
        pa++;
    }
    return pa - start;//Pointer - the pointer gets the number of elements between
}
#include <stdio.h>
int main()
{
    //strlen();- Find string length
    int len1 = my_strlen1("abc");
    int len2 = my_strlen2("abc");
    int len3 = my_strlen3("abc");
    printf("%d\n", len1);
    printf("%d\n", len2);
    printf("%d\n", len3);
    return 0;
}

Pointer + pointer meaningless

Relational operation of pointer

#define N_VALUES 3
for(vp = &values[N_VALUES]; vp > &values[0];)//The comparison between vp and & values [0] here is actually a relational operation
{
    *--vp = 0;
}

Its operation steps are value [3] > values [0] → values[2]=0 → judgment → values[1]=0 → judgment → values[0]=0 → judgment → stop

We rewrite the code:

for(vp = &values[N_VALUES-1]; vp >= &values[0];vp--)
{
    *vp = 0;
}

Its operation steps are values [2] > = & value [0] → values[2]=0 → judgment → values[1]=0 → judgment → values[0]=0 → judgment value [- 1] > = & values [0] → stop execution

Although the second method seems easier to understand and can successfully complete the task on most compilers, we should avoid it because the C language standard does not guarantee its feasibility.
Standard provisions:
A pointer to an array element is allowed to be compared with a pointer to the memory location after the last element of the array, but not with a pointer to the memory location before the first element. It can be remembered that the pointer of the array element is allowed to compare with arr[max+1], but the pointer of the array element is not allowed to compare with arr[-1]

5. Pointer and array

Prove that p+i produces the address with subscript i

int main()
{
    int arr[10]={0};
    int *p=arr;
    int i=0;
    for(i=0;i<10;i++)
    {
        printf("%p<==>%p",&arr[i],p+i);
    }
    return 0;
}

As like as two peas, the address of &arr[i] and p+i is identical, so it can be determined that the address generated by p+i is the address of the array with subscript i, that is, p+i=arr[i].

*Extension:

int main()
{
    int arr[10]={0};
    int *p=arr;
    return 0;
}

Arr [2] < = = > * (P + 2) < = > * (2 + P) / / commutative law
Because both p and arr are the first element addresses, they can also be replaced
arr[2]<==>*(arr+2)<==>*(2+arr)
arr[2]<==>p[2]<==>*(p+2)
We know that [] is an operator and 2 and arr are two operands, so we can exchange positions
arr[2]–>*(arr+2)–>*(2+arr)–>2[arr]

6. Secondary pointer

int main()
{
    int a=10;
    int *pa=&a;//pa is a pointer variable
    int* *ppa=&pa//*ppa first indicates that pa is a pointer, and then int * indicates that the type of pa is int *. At this time, ppa is a secondary pointer variable
    //Dereference - * ppa==pa
    //*pa==a
    //* *ppa==a
    int ** *ppa=&ppa;//Three level pointer, rarely used
    return 0;
}

7. Pointer array

Shaping array: store shaping
Character array: store characters
Pointer array – an array of pointers
For example: int * Parr [5]// Int * indicates that the type of this array is an array of integer pointers

End of this chapter. If you want to have a deeper understanding of pointers, you can see the later advanced pointers

 

Topics: Java C C++ Back-end