[C language]——Advanced pointers (1)

Preface

Through the previous study, we have already understood the basic concepts and usage of pointers. Today I will share with you some pointer exercises and understand some common internship interview questions.
It is mainly divided into nine modules to share:

  1. character pointer
  2. array pointer
  3. array of pointers
  4. Array parameter passing and pointer parameter passing
  5. function pointer
  6. Array of function pointers
  7. Pointer to array of function pointers
  8. Callback
  9. Analysis of pointer and array interview questions

1. Character pointer

Among the types of pointers, we know that there is a pointer type called character pointer char*;

General use:

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

Another way to use it is as follows:

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

The code const char* pstr = “hello bit.”; It is particularly easy for students to think that the hello bit of the string is placed in the character pointer pstr, but the essence is to put the address of the first character of the string hellobit. Arrived in pstr.
Insert image description here
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 bit.";
    char str2[] = "hello bit.";
    const char *str3 = "hello bit.";
    const char *str4 = "hello bit.";
    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 output here is:
Insert image description here

Here str3 and str4 point to the same constant string. C/C++ will store constant strings in a separate memory area as several pointers. When pointing 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. Array pointer

In the chapter "Pointers" we also learned about pointer arrays, which are arrays that store pointers.
Let’s review it again. What does the following pointer array mean?

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

3. Pointer array

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分别是什么?

explain:

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;
}

Insert image description here

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;
}

The running results are as follows:
Insert image description here

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.

In fact: &arr represents the address of the array, not the address of the first element of the array. (Think about it carefully)
In this example, the type of &arr is: int(*)[10], which is an array pointer type. The address of the array + 1, skipping the entire array size, 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];

4. Array parameter passing and pointer parameter passing

When writing code, it is inevitable to pass [array] or [pointer] to the 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?
{
    
    }
void test(int *arr)//ok?
{
    
    }
void test2(int *arr[20])//ok?
{
    
    }
void test2(int **arr)//ok?
{
    
    }
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?
{
    
    }
//总结:二维数组传参,函数形参的设计只能省略第一个[]的数字。
//因为对一个二维数组,可以不知道有多少行,但是必须知道一行多少元素。
//这样才方便运算。
void test(int *arr)//ok?
{
    
    }
void test(int* arr[5])//ok?
{
    
    }
void test(int (*arr)[5])//ok?
{
    
    }
void test(int **arr)//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;
}

think:

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函数能接收什么参数?

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;
}

think:

When the function parameter is a secondary pointer

❓What parameters can be received?

void test(char **p)
{
    
    

}
int main()
{
    
    
 char c = 'b';
 char*pc = &c;
 char**ppc = &pc;
 char* arr[10];
 test(&pc);
 test(ppc);
 test(arr);//Ok?
 return 0;
}

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;
}

Output result:
Insert image description here

The output is two addresses, which are the addresses of the test function.

Then we want to save the address of our function
❓How to save it?
Let’s look at the code:

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.

Read two interesting pieces of code:

//代码1
(*(void (*)())0)();
//代码2
void (*signal(int , void(*)(int)))(int);

Note: Recommended "C Traps and Defects"
This book mentions these two codes.

Code 2 is too complex, how to simplify it:

typedef void(*pfun_t)(int);
pfun_t signal(int, pfun_t);

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 the 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:< /span>

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

A 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 respond to the event or condition.

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;
}

9. Analysis of pointer and array interview questions

one-dimensional array

int a[] = {
    
    1,2,3,4};
printf("%d\n",sizeof(a));
printf("%d\n",sizeof(a+0));
printf("%d\n",sizeof(*a));
printf("%d\n",sizeof(a+1));
printf("%d\n",sizeof(a[1]));
printf("%d\n",sizeof(&a));
printf("%d\n",sizeof(*&a));
printf("%d\n",sizeof(&a+1));
printf("%d\n",sizeof(&a[0]));
printf("%d\n",sizeof(&a[0]+1));

character array

char arr[] = {
    
    'a','b','c','d','e','f'};
printf("%d\n", sizeof(arr));
printf("%d\n", sizeof(arr+0));
printf("%d\n", sizeof(*arr));
printf("%d\n", sizeof(arr[1]));
printf("%d\n", sizeof(&arr));
printf("%d\n", sizeof(&arr+1));
printf("%d\n", sizeof(&arr[0]+1));
printf("%d\n", strlen(arr));
printf("%d\n", strlen(arr+0));
printf("%d\n", strlen(*arr));
printf("%d\n", strlen(arr[1]));
printf("%d\n", strlen(&arr));
printf("%d\n", strlen(&arr+1));
printf("%d\n", strlen(&arr[0]+1));
char arr[] = "abcdef";
printf("%d\n", sizeof(arr));
printf("%d\n", sizeof(arr+0));
printf("%d\n", sizeof(*arr));
printf("%d\n", sizeof(arr[1]));
printf("%d\n", sizeof(&arr));
printf("%d\n", sizeof(&arr+1));
printf("%d\n", sizeof(&arr[0]+1));
printf("%d\n", strlen(arr));
printf("%d\n", strlen(arr+0));
printf("%d\n", strlen(*arr));
printf("%d\n", strlen(arr[1]));
printf("%d\n", strlen(&arr));
printf("%d\n", strlen(&arr+1));
printf("%d\n", strlen(&arr[0]+1));
char *p = "abcdef";
printf("%d\n", sizeof(p));
printf("%d\n", sizeof(p+1));
printf("%d\n", sizeof(*p));
printf("%d\n", sizeof(p[0]));
printf("%d\n", sizeof(&p));
printf("%d\n", sizeof(&p+1));
printf("%d\n", sizeof(&p[0]+1));
printf("%d\n", strlen(p));
printf("%d\n", strlen(p+1));
printf("%d\n", strlen(*p));
printf("%d\n", strlen(p[0]));
printf("%d\n", strlen(&p));
printf("%d\n", strlen(&p+1));
printf("%d\n", strlen(&p[0]+1);

Two-dimensional array

printf("%d\n",sizeof(a));
printf("%d\n",sizeof(a[0][0]));
printf("%d\n",sizeof(a[0]));
printf("%d\n",sizeof(a[0]+1));
printf("%d\n",sizeof(*(a[0]+1)));
printf("%d\n",sizeof(a+1));
printf("%d\n",sizeof(*(a+1)));
printf("%d\n",sizeof(&a[0]+1));
printf("%d\n",sizeof(*(&a[0]+1)));
printf("%d\n",sizeof(*a));
printf("%d\n",sizeof(a[3]));

Summary:
Meaning of array name:

  1. sizeof(array name), the array name here represents the entire array, and the size of the entire array is calculated.
  2. &Array name, the array name here represents the entire array, and the address of the entire array is taken out.
  3. In addition, all array names represent the address of the first element.

Guess you like

Origin blog.csdn.net/weixin_73807021/article/details/129545523