C language - pointers (3) (super detailed)

1.Character pointer variable

1.1 What is a character pointer variable?

int main()
{
    
    
 char ch = 'w';
 char *pc = &ch;//pc就是字符指针变量
const char* p = "abcdefghi";//不是将abcdewfghi\0字符串存放到p中,而是将首字符a的地址存储在p中
//"abcdefghi" 是一个常量字符串,是不能被修改的
//[abcdefghi\0]
//b = 2+3;
//表达式都有2个属性:值属性,类型属性
//2+3 值是5/	//2+3 int
//printf("%c\n", *p);
//*p = 'q';//err
printf("%s\n", p);
return 0;
}

Among them, pc is the character pointer variable. The character pointer variable is used to store the address. const char* p = "abcdefghi"; It is especially easy to think that the string "abcdefghi"; is placed in the character pointer p.

1.2 A written test question related to strings in "Sword Finger Offer"

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

Guess what the result is?
Insert image description here
This is because the array name is actually the first address of the array, and although the contents of the str1 and str2 arrays are the same, (str1 == str2) this is a comparison of addresses, while str3 and str4 are in *The const added before points to the same constant string. When several pointers point to the same string, they will actually point to the same memory. However, 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 the same.

2 array pointer variables

2.1 What is an array pointer?

First of all, we must realize the pointer array we learned before. A pointer array is an array, an array that stores pointers
And what we will learn next:Array pointer
Character pointer - a pointer to a character, which stores the address of the character
char ch = 'w'; char ch * pc = &ch;
Integer pointer - a pointer to an integer, which stores an integer Address
int n = 100; int * p + &n;
Array pointer - a pointer to the array, which stores the address of the array
int arr[10]; int (* p)[10] = &arr; p is the array pointer

2.2 Things to note! ! !

int *p[10] =&arr;It is a pointer array, which is used to store pointers. There is a difference between the two! ! !

int main()
{
    
    
	int arr[6];
	int* p = arr;
	int (*ptr)[6] = &arr;//数组的地址
		//ptr是数组指针

	char* ch[8];
	char* (*p2)[8] = &ch;//p2是数组指针

	int a = 1; int b = 2; int c = 3; int d = 4; int e = 5;
	int* parr[5] = {
    
    &a,&b,&c,&d,&e};//这是指针数组
 
	return 0;
}

The array pointer variable should be: it should store the address of the array, a pointer variable that can point to the array

2.3 Initialization of array pointers

int arr[10] = {
    
    0};
arr;//数组首元素的地址 int *
&arr;//得到的就是数组的地址 int(*)[10]
int(*p)[10] = &arr;

If you want to store the address of an array, you must store it in an array pointer variable, as follows:

Insert image description here
Insert image description here

3 The essence of passing parameters through two-dimensional arrays

First, let’s understand the two-dimensional array again. The two-dimensional array can be regarded as an array in which each element is a one-dimensional array. That is, each element of the two-dimensional array is a one-dimensional array. Then the first element of the two-dimensional array is the first row, which is a one-dimensional array. Therefore, according to the rule that the array name is the address of the first element of the array, the array name of the two-dimensional array represents the address of the first row, which is the address of the one-dimensional array. According to the above example, the type of the one-dimensional array in the first row is int [5], so the type of the address in the first row is the array pointer type int(*)[5]. That means that passing a two-dimensional array parameter essentially also passes the address. What is passed is the address of the one-dimensional array in the first row, so the formal parameters can also be written in pointer form. as follows:

void test(int arr[3][5], int r, int c)	//行参部分写的是数组
{
    
    
	int i = 0;
	int j = 0;
	for (i = 0; i < r; i++)
	{
    
    
		for (j = 0; j < c; j++)
		{
    
    
			printf("%d ", arr[i][j]);
		}
		printf("\n");
	}
}


int main()
{
    
    
	int arr[3][5] = {
    
     {
    
    1,2,3,4,5}, {
    
    2,3,4,5,6}, {
    
    3,4,5,6,7} };
	test(arr, 3, 5);
}//二维数组传参

You can think again that a two-dimensional array is also an array. The array name of a two-dimensional array is also the address of the first element of the array. The passed array name can represent the address of the first element of the array. So, can the row parameter be written as a pointer to receive it?
Insert image description here

code show as below:

void test(int (*arr)[5], int r, int c)
{
    
    
	int i = 0;
	int j = 0;
	for (i = 0; i < r; i++)
	{
    
    
		//*(arr+i) == arr[i]
		int j = 0;
		for (j = 0; j < c; j++)
		{
    
    
			//printf("%d ", *(*(arr + i) + j));
			printf("%d ", arr[i][j]);
			//printf("%d ", (*(arr + i))[j]);
		}
		printf("\n");
	}
}

int main()
{
    
    
	int arr[3][5] = {
    
     {
    
    1,2,3,4,5}, {
    
    2,3,4,5,6}, {
    
    3,4,5,6,7} };
	test(arr, 3, 5);
}//二维数组传参

4. Function pointer variable

4.1 Creation of function pointer variables

Array pointer——It is a pointer——It is a pointer to an array——It is a pointer that stores the array address
Function pointer——It is a pointer——It is a pointer to a function—— It is a pointer that stores the address of the effective function

int Add(int x, int y)
{
    
    
	return x + y;
}

int main()
{
    
    
	//数组名 - 数组首元素的地址
	//&数组名 - 数组的地址

	

	printf("%p\n", &Add);
	printf("%p\n", Add);

	int* p1 = &Add;
	int* p2 = Add;
	
	return 0;
}

Insert image description here
Running results:
Insert image description here
Conclusion:
Functions have addresses, and the function name is the address of the function. Of course, you can also use & function name Method to obtain the address of a function. For a function, (get the address) & the function name and the function name are both the address of the function.

If we want to store the address of the function, we have to create a function pointer variable. The writing method of the function pointer variable is actually very similar to the array pointer. as follows:

void test()
{
    
    
 printf("hehe\n");
}
void (*pf1)() = &test;
void (*pf2)()= test;
int Add(int x, int y)
{
    
    
 return x+y;
}
int(*pf3)(int, int) = Add;
int(*pf3)(int x, int y) = &Add;//x和y写上或者省略都是可以的

Function pointer type analysis:
Insert image description here

4.2 Use of function pointer variables

int Add(int x, int y)
{
    
    
	return x + y;
}

int main()
{
    
    
	int (*pf)(int, int) = Add;//pf函数指针变量

	//int r = pf(3, 5);
	//printf("r = %d\n", r); 

	int r = (*pf)(3, 5); //可以通过(*pf)调用函数
	printf("r = %d\n", r);

	return 0;
}

4.3 Two interesting pieces of code

Next it’s time to learn more:

Code 1:

c( * ( void  ( * ) ( ) ) 0 ) ( );

Let’s first look at what this is?
void ( * p ) ( )
Is it a function pointer?
void ( * ) ( ) This is the function pointer type
Then we add brackets to it
( void ( * ) ( ) )
Now you have to think about it, this is actually a forced type conversion
( void ( * ) ( ) ) 0
We can understand it as forcing the integer 0 to the address of this function. Place a function at address 0 to call it, dereference, and the function has no parameters.
This is understood as ( * p )( )
(* ( void ( * ) ( ) ) 0) (no parameters)

Call the function at address 0. The function called has no parameters and the return type is void.

Code 2:

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

Insert image description here
Will it be clear if we break it down to understand it like this? It can be found that
void (* p) ( int ) is another function pointer type
Insert image description here
Understanding:
signal is the function name of a function, and the above code is a Function declaration. The declared siqnal function has 2 parameters. The first parameter is of int type, and the second parameter is of function pointer type. The function parameter pointed to by the function pointer is of int type, and the return type is the return type of the voidignal function. It is also a function pointer. The function pointed to by the function pointer has an int parameter and a void return type.

Both pieces of code are taken from the book "C Pitfalls and Pitfalls"

4.4typedef keyword

typedef is used to rename types. It can simplify complex types
For example, if you find it inconvenient to write unsigned int, it would be great if you can write it as uint. Then we can use typedef

typedef unsigned int uint;
//将unsigned int 重命名为uint

So if it is a pointer type, can we rename it?
We can rename int to ptr_t:
typedef int* ptr_t;
array pointer type int(
)[5] Renamed to parr_t:
typedef int(*parr_t)[5]; //新的类型名必须在*的右边
Function pointer type void(*)(int) type renamed to pf_t:
typedef void(* pf_t)(int)//新的类型名必须在*的右边

Then the previous functionvoid ( * signal ( int , void ( * ) ( int ) ) ) ( int ); can be written like this?
pf_t signal ( int , pf_t );

typedef void (*pf_t)(int);//typedef在这里重命名时,这里的pf_t是类型名
int main()
{
    
    
pf_t p1;//这里的P1就是函数指针变量
void (*p2)(int);//这里的P2是指针变量的名字
//这两行代码等价
}
pf_t signal(int , pf_t);

Note, don’t think about naming it with Chinese characters

5. Function pointer array

Integer pointer array: array, the array stores all integer pointers
Function pointer array: array, the array stores all function pointers
Store the address of the function in an array, then this array is called a function pointer array

int Add(int x, int y)
{
    
    
	return x + y;
}

int Sub(int x, int y)
{
    
    
	return x - y;
}

int main()
{
    
    
	int* arr[10];//整型指针的数组
	
	//int (* p1)(int,int) = Add;
	//int (* p2)(int,int) = Sub;
	
	//函数指针数组 - 存放函数指针的数组
	int (* pArr[4])(int, int) = {
    
    Add, Sub};//函数指针数组

	return 0;

6.Transfer table

6.1 General implementation of calculator

#include <stdio.h>

int Add(int x, int y)
{
    
    
	return x + y;
}

int Sub(int x, int y)
{
    
    
	return x - y;
}

int Mul(int x, int y)
{
    
    
	return x * y;
}

int Div(int x, int y)
{
    
    
	return x / y;
}
void menu()
{
    
    
	printf("***************************\n");
	printf("*****  1. add  2.sub  *****\n");
	printf("*****  3. mul  4.div  *****\n");
	printf("*****  0. exit        *****\n");
	printf("***************************\n");
}

void calc(int(*pf)(int, int))
{
    
    
	int x = 0;
	int y = 0;
	int ret = 0;

	printf("请输入2个操作数:>");
	scanf("%d %d", &x, &y);
	ret = pf(x, y);
	printf("%d\n", ret);
}

int main()
{
    
    
  int input = 0;

  do
  {
    
    
    menu();
    printf("请选择:>");
    scanf("%d", &input);
    switch (input)
    {
    
    
    case 1:
      calc(Add);
      break;
    case 2:
      calc(Sub);
      break;
    case 3:
      calc(Mul);
      break;
    case 4:
      calc(Div);
      break;
    case 0:
      printf("退出计算器\n");
      break;
    default:
      printf("选择错误, 重新选择\n");
      break;
    }
  } while (input);

  return 0;
}

6.2 Implement a calculator using an array of function pointers:

#include <stdio.h>

int Add(int x, int y)
{
    
    
	return x + y;
}

int Sub(int x, int y)
{
    
    
	return x - y;
}

int Mul(int x, int y)
{
    
    
	return x * y;
}

int Div(int x, int y)
{
    
    
	return x / y;
}


void menu()
{
    
    
	printf("***************************\n");
	printf("*****  1. add  2.sub  *****\n");
	printf("*****  3. mul  4.div  *****\n");
	printf("*****  0. exit        *****\n");
	printf("***************************\n");
}

int main()
{
    
    
	//函数指针的数组
	//转移表
	int (*pfArr[])(int, int) = {
    
    0, Add, Sub, Mul, Div};

	int input = 0;
	int x = 0;
	int y = 0;
	int ret = 0;

	do
	{
    
    
		menu();
		printf("请选择:>");
		scanf("%d", &input);
		if (input >= 1 && input <= 4)
		{
    
    
			printf("请输入2个操作数:>");
			scanf("%d %d", &x, &y);
			ret = pfArr[input](x, y);
			printf("%d\n", ret);
		}
		else if (input == 0)
		{
    
    
			printf("退出计算器\n");
		}
		else
		{
    
    
			printf("选择错误,重新选择\n");
		}
	} while (input);

	return 0;
}

7.qsort usage examples

7.1What is the qsort function?

qsort is a library function used to sort data. It can sort any type of data. How to use it?

Let us first understand the qsort function. The qsort function has 4 parameters.

//void* 是一种指针类型 ,void*类型的指针变量,可以接收任意数据类型的地址
void qsort(

	   void* base, //base指向待排序的第一个元素

       size_t num,  //待排序的元素个数
       
       size_t size, //待排序的数组元素的大小,单位是字节
       
       int (*compar)(const void*e1, const void*e2) 
       //compar是一个函数指针,指向的函数能够比较2个元素);
       //当e1>e2时返回1当e
  

The qsort function uses the idea of ​​[quick sort] to sort data
There are many sorting algorithms: such as bubble sort, selection sort, insertion sort, Hill sort, quick sort …

7.2 Examples of using qsort

Be careful to quote the header file first

#include <stdio.h>
//这个函数能够比较e1和e2指向的两个元素,并且给出返回值
int cmp_int(const void* e1, const void* e2)
{
    
    
	return *(int*)e1 - *(int*)e2;
}

void print_arr(int arr[], int sz)
{
    
    
	int i = 0;
	for (i = 0; i < sz; i++)
	{
    
    
		printf("%d ", arr[i]);
	}
	printf("\n");
}
//test1测试qsort排序整型数组
void test1()
{
    
    
	int arr[] = {
    
     3,1,5,7,2,4,8,6,0,9 };
	int sz = sizeof(arr) / sizeof(arr[0]);
	print_arr(arr, sz);
	qsort(arr, sz, sizeof(arr[0]), cmp_int);
	print_arr(arr, sz);
}
int main()
{
    
    
  test1();
  return 0;
}

The running results are as follows:
Insert image description here

7.3 Simulation implementation of qsort function

Function body

void bubble_sort(void* base, size_t sz, size_t width, int (*cmp)(const void* e1, const void* e2))
{
    
    
    //趟数
    int i = 0;
    for (i = 0; i < sz - 1; i++)
    {
    
    
        //一趟冒泡排序的过程
        int j = 0;
        for (j = 0; j < sz - 1 - i; j++)
        {
    
    
            //if (arr[j] > arr[j + 1])
            if(cmp((char*)base+j*width, (char*)base +(j+1)*width) > 0)
            {
    
    
                //交换
                Swap((char*)base + j * width, (char*)base + (j + 1) * width, width);
            }
        }
    }
}

Function exchange part

void Swap(char* buf1, char* buf2, size_t width)
{
    
    
  int i = 0;
  for (i = 0; i < width; i++)
  {
    
    
    char tmp = *buf1;
    *buf1 = *buf2;
    *buf2 = tmp;
    buf1++;
    buf2++;
  }
}

Next let's test the function

void print_arr(int arr[], int sz)
{
    
    
  int i = 0;
  for (i = 0; i < sz; i++)
  {
    
    
    printf("%d ", arr[i]);
  }
  printf("\n");
}


void test1()
{
    
    
    int arr[] = {
    
     3,1,5,2,4,8,7,6,9,0 };
    int sz = sizeof(arr) / sizeof(arr[0]);
    bubble_sort(arr, sz, sizeof(arr[0]), cmp_int);
    print_arr(arr, sz);
}


int main()
{
    
    
  test1();
  return 0;
}

The running result is as follows:
Insert image description here
The complete code is as follows:

#include <stdio.h>
void Swap(char* buf1, char* buf2, size_t width)
{
    
    
  int i = 0;
  for (i = 0; i < width; i++)
  {
    
    
    char tmp = *buf1;
    *buf1 = *buf2;
    *buf2 = tmp;
    buf1++;
    buf2++;
  }
}

void bubble_sort(void* base, size_t sz, size_t width, int (*cmp)(const void* e1, const void* e2))
{
    
    
    //趟数
    int i = 0;
    for (i = 0; i < sz - 1; i++)
    {
    
    
        //一趟冒泡排序的过程
        int j = 0;
        for (j = 0; j < sz - 1 - i; j++)
        {
    
    
            //if (arr[j] > arr[j + 1])
            if(cmp((char*)base+j*width, (char*)base +(j+1)*width) > 0)
            {
    
    
                //交换
                Swap((char*)base + j * width, (char*)base + (j + 1) * width, width);
            }
        }
    }
}




int cmp_int(const void* e1, const void* e2)
{
    
    
  return *(int*)e1 - *(int*)e2;
}



void print_arr(int arr[], int sz)
{
    
    
  int i = 0;
  for (i = 0; i < sz; i++)
  {
    
    
    printf("%d ", arr[i]);
  }
  printf("\n");
}


void test1()
{
    
    
    int arr[] = {
    
     3,1,5,2,4,8,7,6,9,0 };
    int sz = sizeof(arr) / sizeof(arr[0]);
    bubble_sort(arr, sz, sizeof(arr[0]), cmp_int);
    print_arr(arr, sz);
}

int main()
{
    
    
  test1();
}

Guess you like

Origin blog.csdn.net/2203_75397752/article/details/133997076