Deep understanding of the application of pointers

1. Basic usage of pointers


1. The advantages of using pointers in c programming:

① It can make the program simple, compact and efficient.

② effective representation of complex data structures.

③ Dynamic memory allocation.

④ Get more than one return value.


2. Description of pointer variables

In computer memory, each byte unit has a number called an address.

1 Byte=8 bit 1 byte is equal to 8 bits

In C language, the address of the memory unit is called a pointer, and the variable specially used to store the address is called a pointer variable. In the case of not affecting understanding, sometimes addresses, pointers, and pointer variables are not distinguished, and they are collectively referred to as pointers.

The general form of a pointer variable: <storage type> <data type> *<variable pointer>;

For example: char *pName;

The storage type of the pointer is the data type of the pointer variable itself.

The data type specified in pointer declaration is not the data type of the pointer variable itself, but the data type of the pointer target. A data type referred to simply as a pointer.


3. Pointer initialization

At the same time as the pointer is explained, it can also be given an initial value, which is called pointer initialization. The assignment operation of the pointer refers to sending an address value to the pointer variable through the assignment operator. The value sent must be an address constant or a pointer variable, and cannot be an ordinary integer (except 0).

The general form is: <storage type> <data type> *<variable pointer>=<address amount>;

Common forms of pointer assignment:

①Assign the address of an ordinary variable to a pointer with the same data type.

For example: int a=3; int *pa=&a;

int a,*pa; pa=&a;

② Assign a pointer variable with an existing address value to another pointer variable with the same data type.

For example: float a,*px,*py;

px=&a;

py=px;

③Assign the address of an array to a pointer with the same data type.

For example: int a[20],*pa;

pa=a; or pa=&a[0];

The data in the memory area pointed to by the pointer is called the target of the pointer . If the area it points to is the memory space of a variable in the program, this variable is called the target variable of the pointer . pointer object


Let px be a pointer, then:

px——pointer variable, whose content is the address

*p——The object pointed to by the pointer, its content is data

&px——The address of the storage area occupied by the pointer variable is a constant

Second, the pointer operation

1. Definition and use of operators

Pointer arithmetic is an operation performed on the address stored in a pointer variable as the operand.

The essence of pointer arithmetic is the calculation of addresses.

The types of pointer arithmetic are limited, it can only perform assignment operations, arithmetic operations, and relational operations.

It is meaningless to perform addition and subtraction integer operations on two pointers of different data types.

operator

calculation form

significance

+

PX+n

The pointer moves n data in the direction of the larger address

-

PX-n

The pointer moves n data in the direction of the smaller address

++

PX++ or px++

The pointer moves 1 data in the direction of the larger address

--

px-- or px--

The pointer moves 1 data in the direction of the smaller address

-

PX-PY

The result is the number of data elements separated , not the address

The address of the actual location represented by px+n is: (px) + sizeof(type of px)*n

The address of the actual location represented by px-n is: (px) - sizeof(type of px)*n

2. Exercise 1: pq example

#include <stdio. h>
int main(int argc, char *argv[])
{
int a[5]={4,8,1,2,7};        //p-q示例
int *P, * q;
p = a; //&a[0]; 
q = &a[3];
printf("%p %p\n", p, q);
printf("%d %d\n",*p,*q);
printf("%d\n", q-p);
return 0;
}
打印结果:
 0xbff5b7ac  oxbffb7b8
 4  2
 3

3. Exercise 2: Example of pointer increment and decrement

#include <stdio.h>
int main(int argc,char *argv[]){
int a[5]= {4,8,1,2,7};
int *p,*q;
p= a; //&a[0];
printf("%p %d\n",p,*p);       //指针自增自减示例
q=p++;
printf("%p %d\n",p,*p);
printf("%p %d\n",q,*q);
return 0;
}
打印结果:
0xbfa66e4c   4
0xbfa66e50   8
0xbfa66e4c   4

3. Exercise 3: Use array input and print

Relational operations between two pointers represent the relationship between the address locations they point to. A pointer to a large address is larger than a pointer to a small address.

Relational operations between pointers and general integer variables are meaningless. But you can perform equal or not equal relational operations with zero to judge whether the pointer is empty.

#include <stdio . h>
#define N 5
int main(int argc, char *argv[])
int a[N];
int *p, i;
p=a;//int*p=a;
for(i=6;i<N;i++)
scanf("%d" , p++);//&a[i]
p=a;
for(i=0;i<N;i++){
printf(" %d",*p++);  //++的优先级高,先p++,但是赋值还是之前的赋值给*p
}
puts(" " );
return 0;
}

3. Pointers and arrays

1. Definition and use

In the C language, the pointer of the array refers to the starting address of the array in the memory, and the address of the array element refers to the starting address of the array element in the memory.

The array name of the one-dimensional array is the pointer (start address) of the one-dimensional array.

For example: double x[8]; Therefore, x is the starting address of the x array.


设指针变量px的地址值等于数组指针x (即指针变量px指向数组的首元数), 则:

x[i]、*(px+i)、 *(x+i) 和px[i]具有完全相同的功能:访问数组第i+ 1个数组元素。

注意:指针变量和数组在访问数组中元素时,一定条件 下其使用方法具有相同的形式,因为指针变量和数组名都是地址量.但指针变量和数组的指针(或叫数组名)在本质上不同,指针变量是地址变量)而数组的指针是地址常量。

#include <stdio. h>
int main(int argc, char *argv[])
int a[]={1,6,9,12,61,12,21};
int *p,i, n;
p=a;
n = sizeof(a) / sizeof(int);
printf("%p %p %p\n", a, a+1, a+2);
for(i=0;i<n;i++)
printf("%d %d %d %d\n", a[i], *(p+i), *(a+i), p[i]);
puts(" ");
return 0;
}

2、练习一:编一个程序,实现数组中n个数的翻转。

#include <stdio.h>
int main(int argc, const char *argv[ ] )
{
int a[]={1,2,3,4,5,6};
int *p,*q,n,i, temp;
n=sizeof(a)/sizeof(int);
p=a;
q=&a[n-1];
while(p<q){
temp=*p;
*p=*q;
*q=temp;
p++ ;
q-- ;
}
for (i=0;i<n;i++){
printf( " %d\n",a[i]);
return 0;
}

四、指针与二维数组

多维数组就是具有两个或两个以上下标的数组。

在C语言中,二维数组的元素连续存储,按行优先存。

练习:编程实现,使用一级指针遍历二维数组。

#include <stdio. h>
{
int main(int argc, char *argv[])
int a[3][2] = {
    
    {1, 6}, {9, 12}, {61,12}};
int *p, i, n;
n = sizeof(a) / sizeof(int);
p =a[0]; //&a[0][0];
printf("%p %p\n", p, p+1);      一个一个加
printf("%p %p\n", a, a+1);      一行一行加
for(i=8;i<n;i++)
printf("%d,*(p+i));
puts("") ;
return 0;
}
输出结果:
0xbffeb188 0xbffeb18c
0xbffeb188 0xbffeb190
1 6 9 12 61 12

二维数组名代表数组的起始地址,数组名加1,是移动一行元素。因此,二维数组名常被称为行地址。

行指针(数组指针)

存储行地址的指针变量,叫做行指针变量。形式如下:

●<存储类型> < 数据类型> (* <指针变量名>)[表达式] ;

例如, int a[2][3]; int (*p)[3];

方括号中的常量表达式表示指针加1 , 移动几个数据。

当用行指针操作二维数组时,表达式般写成1行的元素个数,即列数。


1、练习1:编程实现使用行指针表示二维数组int a[3][2]的元素是 a[1][1]

#include <stdio . h>
int main(int argc,char *argv[])
{
int a[3][2] = {
    
    {1, 6},{9, 12},{61,12}};
int (*p)[2];
p=a;
printf("%p %p\n", a, a+1);
printf("%p %p\n", p, p+1);
printf( "%d, %d, %d, %d\n”, a[1][1], p[1][1], *(*(a + 1)+1), *(*(p + 1) +1);
return 0;      //a+1数组先移动一行,加*从行指针变为一级指针,+1再移动一列,加*再取值
}                               
输出结果:
0xbfb52e58 0xbfb52e60
0xbfb52e58 0xbfb52e60 
12,12,12,12

2、练习2:编程实现使用行指针遍历打印出二维数组int a[3][2]的元素

#include <stdio . h>
int main(int argc,char *argv[])
{
int a[3][2] = {
    
    {1, 6},{9, 12},{61,12}};
int (*p)[2];
p=a;
printf("%p %p\n", a, a+1);
printf("%p %p\n", p, p+1);
for(i=0;i<3;i++){
for(j=0;j<2;j++)
printf( "%d, %d, %d, %d\n”, a[i][j], p[i][j], *(*(a + i)+j), *(*(p + i) +j);
}
return 0;      //a+1数组先移动一行,加*从行指针变为一级指针,+1再移动一列,加*再取值
}                               
输出结果:

0xbfb52e58 0xbfb52e60
0xbfb52e58 0xbfb52e60 
1,1,1,1,6,6,6,6
9,9,9,9,12,12,12,12,
61,61,61,61,12,12,12,12

五、字符指针与字符串

1、定义与使用

C语言通过使用字符数组来处理字符串。通常,我们把char数据类型的指针变量称为字符指针变量。字符指针变量与字符数组有着密切关系,它也被用来处理字符事。

#include <stdio.h>
int main(int argc, char *argv[])
{
char ch='A';
char * p;
p = &ch;
printf("%C %c\n", ch, *p);
return 0;
}
输出结果:
A A

初始化字符指针是把内存中字符串的首地址赋予指针,并不是把该字符串复制到指针中

char str[] = "Hello World" ;

char *p =str;

在C编程中,当一个字符指针指向一个字符串常量时,不能修改指针指向的对象的值

例如:char *p="Hello World" ;

*p ='h' ;//错误,字符串常量不能修改

全局变量、static变量、字符串常量放在静态区,程序结束才会结束。

2、练习、不利用任何字符串函数,编程实现字符串连接函数的功能。

int main(int argc, char *argv[])
{
char ch[108] = "welcome" ;
char * p = "hello world!", * q;
int i=0;
q=p;              //保留一下p
while (*(ch+1) != '\0 ) 
i++;
while (*p != '\0') {
(ch+i) = *p;
i++;
p++;
}
*(ch+i) = *p;   //赋以'\0'
p=q;           //保留p
puts(ch);
puts(p);
return 0;
}
输出结果:
welcomehello World!
hello World!

六、指针数组

1、定义与使用

所谓指针数组是指由若干个具有相同存储类型和数据类型的指针变量构成的集合。

指针数组的一般说明形式:

<存储类型> <数据类型> *<指针数组名>[<大小>];

指针数组名表示该指针数组的起始地址.

#include <stdio.>
int main(int argc, char *argv[])
{
int * p[3];//int *....p[0] p[1] p[2]
int a[]={3,6,1,9,18};
p[0] = a;
p[1]=a+1;
p[2]=a+3;
printf( "%d %d %d\n", a[0], a[1], a[3]);
printf"%d %d %d\n",*(p[0]), *(p[1]), *(p[2]);  //[]的优先级大于*,所以()可省略
return 0;
}
输出结果:
3 6 9
3 6 9
#include <stdi0.h>
int main(int argc, char *argv[]) 
int a[2][3] = {
    
    {1, 4, 6},{12, 9, 7}};
int *p[2];
p[0]= a[0];//&a[0][0] 
p[1]= a[1];//&a[1][0]
printf("%d\n", a[0][1]);
printf( %d\n", *(a[0]+1));
printf( %d\n", *(p[0]+1));
return 0;
输出结果:
4
4
4

2、编程:利用指针数组处理一个二维数组 ,要求遍历二维数组所有元素。

#include <stdi0.h>
int main(int argc, char *argv[])
{
int a[2][3] = {
    
    {2, 4, 6},{12, 9, 7};//----a[0] a[1]
p[2] = {a[0], a[1]};
int 1, j;
//printf("%p %p\n", p[0],a[0]); 
//printf("%p %p\n", p[1],a[1]);
for(i=0;i<2;i++){
for(j=0;j<3;j++)
//printf("%d %d ",(a[i) + j),*(p[i]+j));
printf( "%d %d, *(*(a+i) + j),*(*(p+i)+j));
puts(" " ) ;
}
return0;
}

3、编程:利用指针数组处理一个二维数组 ,要求求出二维数组所有元素的和。

#include <stdi0.h>
int main(int argc, char *argv[])
{
int a[2][3] = {
    
    {2, 4, 6},{12, 9, 7};//----a[0] a[1]
p[2] = {a[0], a[1]};
int 1, j,sum=0;
//printf("%p %p\n", p[0],a[0]); 
//printf("%sp %p\n", p[1],a[1]);
for(i=0;i<2;i++){
for(j=0;j<3;j++)
//printf("%d %d ",(a[i) + j),*(p[i]+j));
sum+=*(p[i]+j);
printf( "sum=%d , sum);
puts(" " ) ;
}
return 0;
}
输出结果:sum=39

七、多级指针

1、定义与使用

把一个指向指针变量的指针变量,称为多级指针变量。

对于指向处理数据的指针变量称为一级指针变量,简称一级指针。

而把指向一级指针变量的指针变量称为二级指针变量,简称二级指针。

二级指针变量的说明形式如下

<存储类型> <数据类型> **<指针名> ;

#include <stdio. h>
int main(int argc, char *argv[])
{
int m=10;
int * p; 
int* * q;
p=&m;
q=&p;
printf("%p %p\n", p,&m);
printf("%p %p\n",q,&p);
printf("%d %d %d\n", m, *p, **q);
return 0;
}
输出结果:
0xbfde5884 0xbfde5884
0xbfde5888 0xbfde5888
10 10 10
#include <stdio. h>
int main(int argc, char *argv[])
{
int a[]={3,6,9);
int
p[2] = {&a[0], &a[1]};int ** q;
q = &p[0];//p 
q=p;
printf("%d %d\n", a[0], a[1]);
printf("%d %d\n", *p[0], *p[1]);
printf("%d %d %d\n", a[0], *p[0], **q);
printf("%d %d %d\n", a[1],*p[1], **(q+1));
return 0;
}

2、练习:指针数组的打印

#include <std1o. h>
int main(int argc, char *argv[])
{
//char s1 . "apple";
//char s2 = "pear";
char * s[] = {"apple", "pear”, "potato" }
int i, n;
i=0;
n = sizeof(s) / sizeof(char *);
p=&s[0];  //p=s;
while (i < n){
printf("%s %s\n", s[i],p[i]);
}
return 0;
}

七、void 指针和const修饰符

1、定义与使用

void指针是一种不确定 数据类型的指针变量,它可以通过强制类型转换让该变量指向任何数据类型的变量。一般形式为:void *<指针变量名称> ;

对于void指针,在没有强制类型转换之前,不能进行任何指针的算术运算

#include <stdio . h>
int main(int argc,char *argv[])
{
int m=10;
double n = 3.14;
void *p,*q;
p=&m;//p = (void * )&m;
printf("%d %d\n", m, *(int *)p);
q=&n;//q = (void *)&n;
printf("%.2lf %.2lf\n", n, *(double *)q);
return 0;
}
输出结果:  10  10
          3.14    3.14

2、练习:用void 指针遍历一维数组。

#include <stdio . h>        //方法一
{
int main(int argc, char *argv[])
inta[]={5,9,1,6,9,10};
int i, n;
void * p;
p=a;
n = sizeof(a) / sizeof(int);
for(1=0;1<n;1++)
printf("%d, *((int *)p + i);
puts("");
return 0 ;
}
#include <stdio . h>            //方法二
{
int main(int argc, char *argv[])
{
inta[]={5,9,1,6,9,10};
int i, n;
void *q;
int *p;
q= a;
p = (int *)q;
n = sizeof(a) / sizeof(int);
for(i=0;i<n;i++)
printf("%d”, *(p + i));
puts("");
return 0 ;
}

3、const

const变量:常量化变量的值

const <数据类型>变量名= [<表达式>];

常量化变量是为了使得变量的值不能修改。

变量有const修饰时,若想用指针间接访问变量,指针也要有const修饰。

常量化指针目标表达式

const <数据类型> * <指针变量名称>[= <指针运算表达式>];

常量化指针目标是限制通过指针改变其目标的数值, 但<指针变量>存储的地址值可以修改。

常量化指针变量

<数据类型> * const <指针变量名称>[= <指针运算表达式>];

使得<指针变量>存储的地址值不能修改。但可以通过* <指针变量名称>修改指针所指向变量的数值。

常量化指针变量及其目标表达式

const <数据类型> *const <指针变量名> = <指针运算表达式> ;

常量化指针变量及其目标表达式,使得既不可以修改<指针变量>的地址,也不可以通过* <指针变量名称>修改指针所指向变量的值。

Guess you like

Origin blog.csdn.net/qq_52049228/article/details/129646483