Advanced pointers in C language

Review of primary pointers

1. A pointer is a variable used to store an address. The address uniquely identifies a memory space.
2. The size of the pointer is fixed 4/8 bytes (32-bit platform/64-bit platform).
3. Pointers have types. The type of the pointer determines the +- integer step size of the pointer and the permissions during the pointer dereference operation.
4. Pointer operations.

Next, the blogger will continue with the advanced topic of pointers.

1.Character pointer

Among the types of pointers, we know that there is a pointer type called character pointerchar* ;
Generally used:

int main()
{
    char ch = 'c';
    char *pc = &ch;
    *pc = 'c';
    return 0;
}

Another way to use it is as follows:
 

int main()
{
    const char* pstr = "hello bit.";//这里是把一个字符串放到pstr指针变量里了吗?
    printf("%s\n", pstr);
    return 0;
}

代码 const char* pstr = "hello friend.";

It is particularly easy for us to think that the string hello bit is placed in the character pointer pstr, but the essence is that the address of the first character of the string hello friend. is placed in pstr.

The above code means to store the address of the first character h of a constant string into the pointer variable pstr.
Then there are interview questions like this:
 

#include <stdio.h>
int main()
{
    char str1[] = "hello friend.";
    char str2[] = "hello friend.";
    const char *str3 = "hello friend.";
    const char *str4 = "hello friend.";
    if(str1 ==str2)
    printf("str1 and str2 are same\n");
    else
    printf("str1 and str2 are not same\n");
    if(str3 ==str4)
    printf("str3 and str4 are same\n");
    else
    printf("str3 and str4 are not same\n");
    return 0;
}

The final result is:

Here str3 and str4 point to the same constant string. C/C++ will store constant strings in a separate memory area. When several pointers point to the same string, they will actually point to the same memory. But when using the same constant string to initialize different arrays, different memory blocks will be opened up. So str1 and str2 are different, str3 and str4 are different.

2. Pointer array

What does the following array of pointers mean?

int* arr1[10]; //整形指针的数组
char *arr2[4]; //一级字符指针的数组
char **arr3[5];//二级字符指针的数组

Pointer array is an array
Character array - an array that stores characters
Integer array = an array that stores integers
Pointer array - an array that stores pointers. The elements stored in the array are all pointer types

3. Array pointer

3.1 Definition of array pointer

Is an array pointer a pointer? Or an array?
The answer is: pointers.
We are already familiar with:
Integer pointer: int * pint; A pointer that can point to integer data.
Floating-point pointer: float * pf; A pointer that can point to floating-point data.
The array pointer should be: a pointer that can point to the array.
Which of the following codes is an array pointer?

int *p1[10];
int (*p2)[10];
//p1, p2分别是什么?

Answer:

int (*p)[10];
//解释:p先和*结合,说明p是一个指针变量,然后指着指向的是一个大小为10个整型的数组。所以p是一个
指针,指向一个数组,叫数组指针。
//这里要注意:[]的优先级要高于*号的,所以必须加上()来保证p先和*结合。

3.2 &Array name VS array name

For the following array:

int arr[10];

What are arr and &arr respectively?
We know that arr is the array name, and the array name represents the address of the first element of the array.
So ​​what is the name of the &arr array?
Let’s look at a piece of code:
 

#include <stdio.h>
int main()
{
    int arr[10] = {0};
    printf("%p\n", arr);
    printf("%p\n", &arr);
    return 0;
}

The running results are as follows:

It can be seen that the address printed by the array name and &array name is the same.
Are the two the same?
Let’s look at another piece of code:

#include <stdio.h>
int main()
{
    int arr[10] = { 0 };
    printf("arr = %p\n", arr);
    printf("&arr= %p\n", &arr);
    printf("arr+1 = %p\n", arr+1);
    printf("&arr+1= %p\n", &arr+1);
    return 0;
}

According to the above code, we found that in fact, although the values ​​​​of &arr and arr are the same, their meanings should be different.
Actually: &arr represents the address of the array, and Not the address of the first element of the array. (Think about it carefully)
In this example, the type of &arr is: int(*)[10] , is the address of an array pointer type array + 1, skipping the size of the entire array, so & The difference between arr+1 and &arr is 40.

3.3 Use of array pointers

How to use array pointers?
Since the array pointer points to an array, the array pointer should store the address of the array.
Look at the code:

#include <stdio.h>
int main()
{
    int arr[10] = {1,2,3,4,5,6,7,8,9,0};
    int (*p)[10] = &arr;//把数组arr的地址赋值给数组指针变量p
    //但是我们一般很少这样写代码
    return 0;
}

Use of an array pointer:
 

#include <stdio.h>
void print_arr1(int arr[3][5], int row, int col)
{
    int i = 0;
    for(i=0; i<row; i++)
    {
        for(j=0; j<col; j++)
        {
        printf("%d ", arr[i][j]);
        }
        printf("\n");
    }
}
void print_arr2(int (*arr)[5], int row, int col)
{
    int i = 0;
    for(i=0; i<row; i++)
    {
        for(j=0; j<col; j++)
        {
            printf("%d ", arr[i][j]);
        }
        printf("\n");
    }
}
int main()
{
    int arr[3][5] = {1,2,3,4,5,6,7,8,9,10};
    print_arr1(arr, 3, 5);
    //数组名arr,表示首元素的地址
    //但是二维数组的首元素是二维数组的第一行
    //所以这里传递的arr,其实相当于第一行的地址,是一维数组的地址
    //可以数组指针来接收
    print_arr2(arr, 3, 5);
    return 0;
}

After learning about pointer arrays and array pointers, let’s review them together and see what the following code means:

int arr[5];
int *parr1[10];
int (*parr2)[10];
int (*parr3[10])[5];

There is no doubt that arr is an integer array

Let's look at the back. Parr1 is an array. The array has 10 elements. The type of each element is int *

parr2 is an array pointer, because * is first combined with parr2. The pointer points to the array. The array pointed to has 10 elements, all of type Int.

parr3 is an array, which stores array pointers. The array pointed to by the stored array pointer has 5 elements, and each element is of type int. Because parr3 is first combined with [10], take away parr3[10], and the remaining int(*)[5] is its type.

4. Array parameters, pointer parameters 

 When writing code, it is inevitable to pass [array] or [pointer] to a function. How should the parameters of the function be designed?

4.1 One-dimensional array parameter transfer

#include <stdio.h>
void test(int arr[])//ok?  数组传参,形参部分写成数组是可以的,这里传入首地址,所以大小可以省略
{}
void test(int arr[10])//ok?  如上,所以是OK的
{}
void test(int *arr)//ok?   数组传参的本质是,传递了数组的首元素地址,所以可以是指针类型 
{}
void test2(int *arr[20])//ok?  test2是个整型指针,所以形参也可用整型指针
{}
void test2(int **arr)//ok?    test2的每个类型都是int *,用int **没毛病,二级指针接收一级指针
{}
int main()
{
    int arr[10] = {0};
    int *arr2[20] = {0};
    test(arr);
    test2(arr2);
}

 4.2 Two-dimensional array parameter transfer

void test(int arr[3][5])//ok?二维数组用二维数组为形参,没问题
{}
void test(int arr[][])//ok? 二维数组的行可省略,列不能省略
{}
void test(int arr[][5])//ok? 这是个二维数组,行省略,列没省略,所以OK
{}
//总结:二维数组传参,函数形参的设计只能省略第一个[]的数字。
//因为对一个二维数组,可以不知道有多少行,但是必须知道一行多少元素。
//这样才方便运算。
void test(int *arr)//ok?二维数组的数组名实际上传的是第一行的地址,不能用整型指针
{}
void test(int* arr[5])//ok? 如上,不OK
{}
void test(int (*arr)[5])//ok?形参是个数组指针,存放数组,没问题
{}
void test(int **arr)//ok?二级指针接收的是一级指针,不OK
{}
int main()
{
int arr[3][5] = {0};
test(arr);
}

4.3 First-level pointer parameter passing

#include <stdio.h>
void print(int *p, int sz)
{
    int i = 0;
    for(i=0; i<sz; i++)
    {
    printf("%d\n", *(p+i));
    }
}
int main()
{
    int arr[10] = {1,2,3,4,5,6,7,8,9};
    int *p = arr;
    int sz = sizeof(arr)/sizeof(arr[0]);
    //一级指针p,传给函数
    print(p, sz);
    return 0;
}

Thinking:
When the parameter part of a function is a first-level pointer, what parameters can the function receive?
For example:
 

void test1(int *p)
{}
//test1函数能接收什么参数?
void test2(char* p)
{}
//test2函数能接收什么参数?

The test1 function can receive an integer address, for example:

int a = 10;
test(&a);

It can also be done like this:

int a = 10;
int * ptr = &a;
test(ptr);

It can also be like this:

int arr[5];
text(arr);

Summary: You can pass the array name of an integer one-dimensional array, an integer pointer, and the address of an integer variable.

4.4 Second-level pointer parameter passing

#include <stdio.h>
void test(int** ptr)
{
    printf("num = %d\n", **ptr);
}
int main()
{
    int n = 10;
    int*p = &n;
    int **pp = &p;
    test(pp);
    test(&p);
    return 0;
}

Thinking: When the parameter of a function is a secondary pointer, what parameters can it receive?

void test(char **p)
{ }
int main()
{
    char c = 'b';
    char*pc = &c;
    char**ppc = &pc;
    char* arr[10];
    test(&pc); pc是一级指针,&pc是二级指针,所以OK
    test(ppc);  二级指针传二级指针,没问题
    test(arr);//Ok? OK,数组名表首元素地址,传递的是指针数组的首元素地址,是一级指针
    return 0;
}

Summary: The second-level pointer is a parameter and can receive: first-level pointer, second-level pointer, and pointer array.

5. Function pointer

 First look at a piece of code:

#include <stdio.h>
void test()
{
    printf("hehe\n");
}
int main()
{
    printf("%p\n", test);
    printf("%p\n", &test);
    return 0;
}

outputs two addresses, which are the addresses of the test function.

So if we want to save the address of our function, how do we save it?

Let's look at the code below:

void test()
{
    printf("hehe\n");
}
//下面pfun1和pfun2哪个有能力存放test函数的地址?
void (*pfun1)();
void *pfun2();

First of all, to be able to give the storage address, it requires pfun1 or pfun2 to be a pointer. So which one is the pointer?
The answer is:
pfun1 can be stored. pfun1 is first combined with *, indicating that pfun1 is a pointer. The pointer points to a function. The pointed function has no parameters and the return value type is void.

6. Array of function pointers

An array is a storage space that stores data of the same type. We have already learned about pointer arrays,
For example:

int *arr[10];
//数组的每个元素是int*

Then the address of the function must be stored in an array. Then this array is called a function pointer array. How to define the array of function pointers?
?

int (*parr1[10])();
int *parr2[10]();
int (*)() parr3[10];

The answer is: parr1
Parr1 is first combined with [] to indicate that parr1 is an array. What is the content of the array?
is a function pointer of type int (*)().

Use of function pointer array: transfer table
Example: (calculator)
 

#include <stdio.h>
int add(int a, int b)
{
    return a + b;
}
    int sub(int a, int b)
{
    return a - b;
}
    int mul(int a, int b)
{
    return a*b;
}
    int div(int a, int b)
{
    return a / b;
}
int main()
{
    int x, y;
    int input = 1;
    int ret = 0;
    do
    {
        printf( "*************************\n" );
        printf( " 1:add 2:sub \n" );
        printf( " 3:mul 4:div \n" );
        printf( "*************************\n" );
        printf( "请选择:" );
        scanf( "%d", &input);
        switch (input)
        {
        case 1:
            printf( "输入操作数:" );
            scanf( "%d %d", &x, &y);
            ret = add(x, y);
            printf( "ret = %d\n", ret);
            break;
        case 2:
            printf( "输入操作数:" );
            scanf( "%d %d", &x, &y);
            ret = sub(x, y);
            printf( "ret = %d\n", ret);
            break;
        case 3:
            printf( "输入操作数:" );
            scanf( "%d %d", &x, &y);
            ret = mul(x, y);
            printf( "ret = %d\n", ret);
            break;
        case 4:
            printf( "输入操作数:" );
            scanf( "%d %d", &x, &y);
            ret = div(x, y);
            printf( "ret = %d\n", ret);
            break;
        case 0:
            printf("退出程序\n");
            breark;
        default:
            printf( "选择错误\n" );
            break;
        }
    } while (input);
    return 0;
}

Implementation using array of function pointers:
 

#include <stdio.h>
int add(int a, int b)
{
return a + b;
}
int sub(int a, int b)
{
return a - b;
}
int mul(int a, int b)
{
return a*b;
}
int div(int a, int b)
{
return a / b;
}
int main()
{
    int x, y;
    int input = 1;
    int ret = 0;
    int(*p[5])(int x, int y) = { 0, add, sub, mul, div }; //转移表
    while (input)
    {
        printf( "*************************\n" );
        printf( " 1:add 2:sub \n" );
        printf( " 3:mul 4:div \n" );
        printf( "*************************\n" );
        printf( "请选择:" );
        scanf( "%d", &input);
        if ((input <= 4 && input >= 1))
        {
            printf( "输入操作数:" );
            scanf( "%d %d", &x, &y);
            ret = (*p[input])(x, y);
        }
        else
            printf( "输入有误\n" );
        printf( "ret = %d\n", ret);
    }
    return 0;
}

7. Pointer to array of function pointers

The pointer to an array of function pointers is a pointer
The pointer points to an array, and the elements of the array are function pointers;
How to define?
 

void test(const char* str)
{
    printf("%s\n", str);
}
int main()
{
    //函数指针pfun
    void (*pfun)(const char*) = test;
    //函数指针的数组pfunArr
    void (*pfunArr[5])(const char* str);
    pfunArr[0] = test;
    //指向函数指针数组pfunArr的指针ppfunArr
    void (*(*ppfunArr)[5])(const char*) = &pfunArr;
    return 0;
}

8. Callback function

The callback function is a function called through a function pointer. If you pass a function pointer (address) as a parameter to another
function, and when this pointer is used to call the function it points to, we say it is a callback function. The callback function is not called directly by the implementer of the function
, but is called by another party when a specific event or condition occurs to evaluate the event or condition
line response.
First demonstrate the use of the qsort function:
 

#include <stdio.h>
//qosrt函数的使用者得实现一个比较函数
int int_cmp(const void * p1, const void * p2)
{
    return (*( int *)p1 - *(int *) p2);
}
int main()
{
    int arr[] = { 1, 3, 5, 7, 9, 2, 4, 6, 8, 0 };
    int i = 0;
    qsort(arr, sizeof(arr) / sizeof(arr[0]), sizeof (int), int_cmp);
    for (i = 0; i< sizeof(arr) / sizeof(arr[0]); i++)
    {
        printf( "%d ", arr[i]);
    }
    printf("\n");
    return 0;
}

Use the callback function to simulate the implementation of qsort (using bubbling method)

Note: This is the first time that the void* pointer is used to explain the role of void*.

#include <stdio.h>
int int_cmp(const void * p1, const void * p2)
{
    return (*( int *)p1 - *(int *) p2);
}
void _swap(void *p1, void * p2, int size)
{
    int i = 0;
    for (i = 0; i< size; i++)
    {
        char tmp = *((char *)p1 + i);
        *(( char *)p1 + i) = *((char *) p2 + i);
        *(( char *)p2 + i) = tmp;
    }
}
void bubble(void *base, int count , int size, int(*cmp )(void *, void *))
{
    int i = 0;
    int j = 0;
    for (i = 0; i< count - 1; i++)
    {
        for (j = 0; j<count-i-1; j++)
        {
            if (cmp ((char *) base + j*size , (char *)base + (j + 1)*size) > 0)
            {
                _swap(( char *)base + j*size, (char *)base + (j + 1)*size, size);
            }
        }
    }
}
int main()
{
    int arr[] = { 1, 3, 5, 7, 9, 2, 4, 6, 8, 0 };
    //char *arr[] = {"aaaa","dddd","cccc","bbbb"};
    int i = 0;
    bubble(arr, sizeof(arr) / sizeof(arr[0]), sizeof (int), int_cmp);
    for (i = 0; i< sizeof(arr) / sizeof(arr[0]); i++)
    {
        printf( "%d ", arr[i]);
    }
    printf("\n");
    return 0;
}


 

Guess you like

Origin blog.csdn.net/A1546553960/article/details/133532453