Section 2. Advanced pointer

Posted by TutorMe on Tue, 18 Jan 2022 12:45:44 +0100

Section 2. Advanced pointer

1. Character pointer

Among the pointer types, we know that one pointer type is character pointer char *;

be careful:

 const char* pstr = "hello";

Instead of putting the string hello into the character pointer pstr, the essence is to put the address of the first character of the string hello into pstr.

#include <stdio.h>
int main() {
    char str1[] = "hello";
    char str2[] = "hello";
    const char *str3 = "hello";
    const char *str4 = "hello";
    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;
} 

//str1 and str2 are not same
//str3 and str4 are same

Here, str3 and str4 point to the same constant string.

C/C + + will store the constant string in a separate memory area when several pointers. When pointing to the same string, they actually point to the same block of memory. However, when initializing different arrays with the same constant string, different memory blocks will be opened up.

So str1 and str2 are different, and str3 and str4 are the same.

2. Pointer array

Pointer array is an array of pointers.

int* arr1[10]; //Array of integer pointers
char* arr2[10]; //Array of first level character pointers
char** arr3[10];//Array of secondary character pointers

3. Array pointer

3.1 definitions

Array pointers are pointers that can point to arrays.

int (*p)[10];
//Explanation: P is first combined with * to indicate that P is a pointer variable, and then points to an array of 10 integers. So p is a pointer to an array, called an array pointer.

//Note here that the priority of [] is higher than that of * sign, so () must be added to ensure that p is combined with * first.

3.2 "array name" vs "& array name"

int arr[10];

Are arr and & arr the same thing?

for instance:

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

result:

arr = 012FF6EC

arr+1 = 012FF6F0

&arr= 012FF6EC

&arr+1= 012FF714

From the results of the above code, we can see that & arr and arr have the same value, but they are essentially different.

actually:

arr is the array name, which indicates the address of the first element of the array.

&Arr represents the address of the array, not the address of the first element of the array.

In this example, the type of & arr is int(*)[10], which is an array pointer type

The address of the array is + 1, skipping the size of the entire array, so the difference between & arr + 1 and & arr is 40

4. Function pointer

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

result:

003A1474

003A1474

Two addresses are output, which are the addresses of the test function. So, how to save the address of the function?

void test() {
    printf("hehe\n");
} 
void (*pfun)(); //pfun is a pointer to a function

Add two interesting pieces of code:

//Code 1
( *( void (*)() )0 )();
//Convert 0 to function pointer type without reference and no return value, and then invoke 0 after invoking.
//Is to call the function at address 0

//Code 2
void ( *signal( int , void(*)(int) ) )(int);
//signal is a function declaration
//This function has two parameters, one is int and the other is a function pointer. The function parameter pointed by the pointer is int and the return type is void
//The return type of signal function is also a function pointer. The pointer points to the function parameter int, and the return type is void
//Simplified version
typedef void(* pfun_t)(int);
pfun_t signal(int,pfun_t);

5. Function pointer array

Array is a storage space for storing the same type of data, and pointer array is an array for storing pointers.

If the address of the function is stored in an array, this array is called the function pointer array.

int (*parr[10])();

Purpose of function pointer array: transfer table

example:

Use the function pointer array to implement the 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;
    int(*p[5])(int x, int y) = { 0, add, sub, mul, div }; //Transfer table     
    while (input){
        printf( "*************************\n" );
        printf( "  1:add           2:sub  \n" );
        printf( "  3:mul           4:div  \n" );
        printf( "*************************\n" );
        printf( "Please select:" );
        scanf( "%d", &input);
        if ((input <= 4 && input >= 1)){
            printf("Input operand:");
            scanf("%d %d", &x, &y);
            ret = (*p[input])(x, y);
        }else{
            printf( "Incorrect input\n" );
        }
        printf( "ret = %d\n", ret);
    }
    return 0;
}

6. Pointer to function pointer array

The pointer to the array of function pointers is a pointer

The pointer points to an array whose elements are function pointers

void test(const char* str){
	printf("%s\n", str);
}
int main(){
	//Function pointer pfun
	void (*pfun)(const char*) = test;
    
	//Array of function pointers pfunArr
	void (*pfunArr[5])(const char* str);
	pfunArr[0] = test;
    
	//Pointer to function pointer array pfunArr ppfunArr
	void (*(*ppfunArr)[5])(const char*) = &pfunArr;
    
	return 0;
}

7. Callback function

A callback function is a function called through a function pointer.

If you pass the pointer (address) of a function as a parameter to another function, when the 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 by another party when a specific event or condition occurs, which is used to respond to the event or condition.

for instance:

First, demonstrate the use of qsort function (quick sort):

The qsot function can sort any type of data

#include <stdio.h>
//The user of the qosrt function must implement a comparison function
//void * is a pointer without a specific type
//The pointer variable of void * can store any type of address
//The pointer of void * cannot be dereferenced and + - * / directly
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 (bubbling)

#include <stdio.h>
//Comparison function
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;
}

8. Written test questions for pointers and arrays

X86 environment

(the address size is 4 in X86 environment and 8 in X64 environment)

//One dimensional array
int a[] = {1,2,3,4};
printf("%d\n",sizeof(a));        //16 (the array name a is placed separately in sizeof to calculate the size of the whole array)
printf("%d\n",sizeof(a+0));      //4 (a represents the address of the first element, and a+0 also represents the address of the first element)
printf("%d\n",sizeof(*a));       //4 (* a indicates dereference of the first element address)
printf("%d\n",sizeof(a+1));      //4 (a represents the address of the first element, and a+1 represents the address of the second element)
printf("%d\n",sizeof(a[1]));     //4 (a[1] is the second element of the array)
printf("%d\n",sizeof(&a));       //4 (& A represents the address of the array)
printf("%d\n",sizeof(*&a));      //16 (* & A indicates dereference to the address of the array)
printf("%d\n",sizeof(&a+1));     //4 (& A + 1 address after skipping the entire array)
printf("%d\n",sizeof(&a[0]));    //4 (& A [0] indicates the address of the first element of the array)
printf("%d\n",sizeof(&a[0]+1));  //4 (& A [0] + 1 indicates the address of the second element of the array)

//Character array
char arr[] = {'a','b','c','d','e','f'};
printf("%d\n", sizeof(arr));        //6
printf("%d\n", sizeof(arr+0));      //4
printf("%d\n", sizeof(*arr));       //1
printf("%d\n", sizeof(arr[1]));     //1
printf("%d\n", sizeof(&arr));       //4
printf("%d\n", sizeof(&arr+1));     //4
printf("%d\n", sizeof(&arr[0]+1));  //4

printf("%d\n", strlen(arr));        //Random value because there is no '\ 0' at the end
printf("%d\n", strlen(arr+0));      //Random value because there is no '\ 0' at the end
printf("%d\n", strlen(*arr));       //If an error is reported, strlen will take 97 ('a 'ascii value) as the starting address statistics string, resulting in memory access conflict
printf("%d\n", strlen(arr[1]));     //Error reporting, ibid
printf("%d\n", strlen(&arr));       //Error reported, & arr is the address of the ARR array, which does not match the parameter type
printf("%d\n", strlen(&arr+1));     //Error reporting, ibid
printf("%d\n", strlen(&arr[0]+1));  //Random value because there is no '\ 0' at the end
//sizeof is an operator of any type
//sizeof gets the storage space occupied by the data in the memory, which is counted in bytes
//strlen is a library function for strings
//strlen focuses on the position of '\ 0' in the string and calculates the number of characters before '\ 0'

char arr[] = "abcdef";
printf("%d\n", sizeof(arr));        //7
printf("%d\n", sizeof(arr+0));      //4
printf("%d\n", sizeof(*arr));       //1
printf("%d\n", sizeof(arr[1]));     //1
printf("%d\n", sizeof(&arr));       //4
printf("%d\n", sizeof(&arr+1));     //4
printf("%d\n", sizeof(&arr[0]+1));  //4

printf("%d\n", strlen(arr));        //6
printf("%d\n", strlen(arr+0));      //6
printf("%d\n", strlen(*arr));       //If an error is reported, strlen will take 97 ('a 'ascii value) as the starting address statistics string, resulting in memory access conflict
printf("%d\n", strlen(arr[1]));     //Error reporting, ibid
printf("%d\n", strlen(&arr));       //Error reported, & arr is the address of the ARR array, which does not match the parameter type
printf("%d\n", strlen(&arr+1));     //Error reporting, ibid
printf("%d\n", strlen(&arr[0]+1));  //5

char *p = "abcdef";
printf("%d\n", sizeof(p));          //4
printf("%d\n", sizeof(p+1));        //4
printf("%d\n", sizeof(*p));         //1
printf("%d\n", sizeof(p[0]));       //1
printf("%d\n", sizeof(&p));         //4
printf("%d\n", sizeof(&p+1));       //4
printf("%d\n", sizeof(&p[0]+1));    //4

printf("%d\n", strlen(p));          //6
printf("%d\n", strlen(p+1));        //5
printf("%d\n", strlen(*p));         //report errors
printf("%d\n", strlen(p[0]));       //report errors
printf("%d\n", strlen(&p));         //report errors
printf("%d\n", strlen(&p+1));       //report errors
printf("%d\n", strlen(&p[0]+1));    //5

//Two dimensional array
int a[3][4] = {0};
printf("%d\n",sizeof(a));           //48
printf("%d\n",sizeof(a[0][0]));     //4
printf("%d\n",sizeof(a[0]));        //16
printf("%d\n",sizeof(a[0]+1));      //4
printf("%d\n",sizeof(*(a[0]+1)));   //4
printf("%d\n",sizeof(a+1));         //4
printf("%d\n",sizeof(*(a+1)));      //16
printf("%d\n",sizeof(&a[0]+1));     //4
printf("%d\n",sizeof(*(&a[0]+1)));  //16
printf("%d\n",sizeof(*a));          //16
printf("%d\n",sizeof(a[3]));        //16

Summary:
Meaning of array name:

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

9. Pointer written test questions

Written test question 1

int main(){
	int a[5] = { 1, 2, 3, 4, 5 };
	int *ptr = (int *)(&a + 1);
	printf( "%d,%d", *(a + 1), *(ptr - 1));
	return 0;
}
//2,5

Written test question 2

struct Test{
	int Num;
	char *pcName;
	short sDate;
	char cha[2];
	short sBa[4];
}*p;

int main(){
	printf("%p\n", p + 0x1);
	printf("%p\n", (unsigned long)p + 0x1);
	printf("%p\n", (unsigned int*)p + 0x1);
	return 0;
}
//00000014
//00000001
//00000004

Written test question 3

int main(){
	int a[4] = { 1, 2, 3, 4 };
	int *ptr1 = (int *)(&a + 1);
	int *ptr2 = (int *)((int)a + 1);
	printf( "%x,%x", ptr1[-1], *ptr2);
	return 0;
}
//4,2000000

Written test question 4

int main(){
	int a[3][2] = { (0, 1), (2, 3), (4, 5) };
	int *p;
	p = a[0];
	printf("%d", p[0]);
	return 0;
}
//1

Written test question 5

int main(){
	int a[5][5];
	int(*p)[4];
	p = a;
	printf( "%p,%d\n", &p[4][2] - &a[4][2], &p[4][2] - &a[4][2]);
	return 0;
}
//FFFFFFFC,-4

Written test question 6

int main(){
	int aa[2][5] = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 };
	int *ptr1 = (int *)(&aa + 1);
	int *ptr2 = (int *)(*(aa + 1));
	printf( "%d,%d", *(ptr1 - 1), *(ptr2 - 1));
	return 0;
}
//10,5

Written test question 7

int main(){
	char *a[] = {"work","at","alibaba"};
	char**pa = a;
	pa++;
	printf("%s\n", *pa);
	return 0;
}
//at

Written examination question 8

int main(){
	char *c[] = {"ENTER","NEW","POINT","FIRST"};
	char**cp[] = {c+3,c+2,c+1,c};
	char***cpp = cp;
	printf("%s\n", **++cpp);
	printf("%s\n", *--*++cpp+3);
	printf("%s\n", *cpp[-2]+3);
	printf("%s\n", cpp[-1][-1]+1);
	return 0;
}
//POINT
//ER
//ST
//EW

10. Appendix (use of qsort)

#include<string.h>
#include<stdio.h>
#include<stdlib. h> / / header file for qsort

struct Student{
	int id;
	char name[50];	
};

int int_cmp(const void* a, const void* b){
	return *(int*)a - *(int*)b;
}
int char_cmp(const void* a, const void* b){
	return *(char*)a - *(char*)b;
}
int double_cmp(const void* a, const void* b){
	return *(double*)a > *(double*)b ? 1 : -1;
}
int struct_cmp(const void* a, const void* b) {
	return ((struct Student*)a)->id - ((struct Student*)b)->id;
}
int str_cmp(const void* a, const void* b) {
	return strcmp(*(char**)a, *(char**)b);
}

int main() {
    //int sort
	int num[5] = { 1,3,9,5,2 };
	qsort(num, sizeof(num) / sizeof(num[0]), sizeof(num[0]), int_cmp);
	for (int i = 0; i < sizeof(num) / sizeof(num[0]); i++) {
		printf("%d ", num[i]);
	}
	printf("\n");
	//char sort
	char word[5] = "CADB";
	qsort(word, sizeof(word) / sizeof(word[0]), sizeof(word[0]), char_cmp);
	for (int i = 0; i < sizeof(word) / sizeof(word[0]); i++) {
		printf("%c ", word[i]);
	}
	printf("\n");
	//double sort
	double in[5] = { 1.23,3.14159,2.6,5.74,4.11 };
	qsort(in, sizeof(in) / sizeof(in[0]), sizeof(in[0]), double_cmp);
	for (int i = 0; i < sizeof(in) / sizeof(in[0]); i++) {
		printf("%lf ", in[i]);
	}
	printf("\n");
	//struct sort
	struct Student stu[3] = { {2,"Xiao Ming"},{1,"petty thief"},{3,"Xiao Hong"} };
	qsort(stu, sizeof(stu) / sizeof(stu[0]), sizeof(stu[0]), struct_cmp);
	for (int i = 0; i < sizeof(stu) / sizeof(stu[0]); i++) {
		printf("%d%s ", stu[i].id,stu[i].name);
	}
	printf("\n");
	//string sort
	char *str[5] = { "AAA","EEE","CCC","BBB","DDD" };
	qsort(str, sizeof(str) / sizeof(str[0]), sizeof(str[0]), str_cmp);
	for (int i = 0; i < sizeof(str) / sizeof(str[0]); i++) {
		printf("%s ", str[i]);
	}
	printf("\n");

	return 0;
}

Topics: C