本文主要讲解了c语言中指针的进阶内容,在初阶的基础上进行延伸.
内存会划分为一个个的内存单元
每个内存单元都有一个独立的编号,-编号也称为地址
地址在C语言中也被称为指针
指针(地址)需要存储起来-存储到变量中,这个变量也就被称为指针变量
指针(地址)的大小固定说4/8个字节(32位平台/64位平台)
地址是物理的电线上产生
32为机器-32根地址线 -1/0
32个0/1组成的二进制序列,把这个二进制序列作为地址,32bit位才能存储这个地址
也就是需要4个字节才能存储,所以指针变量的大小是4个字节
同理64位机器上,地址的大小是64个0/1组成的二进制序列,需要64bit位存储,也就是8个字节。所以指针变量的大小是8个字节。
在指针的类型中我们知道有一种指针类型为字符指针char*
//在指针的类型中我们知道有一种指针类型为字符指针char*
int main()
{
char ch = 'w';
char* pc = &ch; //pc就是字符指针
*pc = 'a';
char arr[] = "abcdef"; //[a b c d e f \0]
const char*p = "abcdef"; //常量字符串
printf("%s\n",p); //abcdef
printf("%c\n",*p); //a
return 0;
}
经典面试题小试牛刀
int main()
{
char str1[] = "hello xiaofan.";
char str2[] = "hello xiaofan.";
const char* str3 = "hello xiaofan.";
const char* str4 = "hello xiaofan.";
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;
}
数组指针是数组还是指针 ----是指针哦
数组指针类比:
整型指针-指向整型变量的指针,存放整型变量的地址的指针变量
字符指针-指向字符变量的指针,存放字符变量的地址的指针变量
数组指针-指向数组的指针,存放的是数组的地址的指针变量
//数组指针
//数组名的理解
//数组名是数组首元素的地址
//2个例外:1.sizeof(数组名),这里的数组名不是数组首元素的地址,数组名表示整个数组,sizeof(数组名)计算的是整个数组的大小,单位是字节
//2.&数组名,这里的数组名表示整个数组,&数组名取出的是整个数组的地址
//除此之外,所有的地方的数组名都是数组首元素的地址
// int main()
// {
// int arr[10] = {0};
// printf("%p\n",arr); // int*
// printf("%p\n",arr+1);
// printf("%p\n",&arr[0]); //int*
// printf("%p\n",&arr[0]+1);
// printf("%p\n",&arr); //int(*)[10]
// printf("%p\n",&arr+1);
// return 0;
// }
//对于数组名来说
//&数组名得到的是数组的地址
// int main()
// {
// int arr[10] = {1,2,3,4,5,6,7,8,9,10};
// //数组的地址,存储到数组指针变量
// //int[10] *p = &arr; //err
// int(*p)[10] = &arr;
// }
// int main()
// {
// int arr[10] = {1,2,3,4,5,6,7,8,9,10};
// int* p = arr;
// int i = 0;
// for (i = 0;i<10;i++)
// {
// printf("%d ",*(p+i));
// }
// }
// int main()
// {
// int arr[10] = {1,2,3,4,5,6,7,8,9,10};
// int (*p)[10] = &arr; //*&arr -> arr
// int i = 0;
// for (i = 0;i<10;i++)
// {
// printf("%d ",*((*p)+i));
// printf("%d ",(*p)[i]);
// }
// }
//数组指针怎么使用呢?一般在二维数组上才方便
//二维数组传参,形参是二维数组的形式
// void Printf(int arr[3][5],int r,int c)
// {
// int i = 0;
// for (i = 0; i<3;i++)
// {
// int j = 0;
// for(j = 0;j < 5;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};
// Printf(arr,3,5);
// return 0;
// }
//二维数组传参,形参是指针的形式
// void Printf(int (*p)[5],int r,int c)
// {
// int i = 0;
// for(i = 0; i < r; i++)
// {
// int j = 0;
// for (j = 0; j < c; j++)
// {
// printf("%d ",*(*(p+i)+j));
// }
// }
// }
// //二维数组的每一行可以理解为二维数组的一个元素
// //每一行又是一个一维数组
// //二维数组其实是一维数组的数组
// //二维数组的数组名,也是数组名,数组名就是数组首元素地址
// //arr - 首元素地址 - 第一行的地址 -一维数组的地址 -数组的地址
// int main()
// {
// int arr[3][5] = {1,2,3,4,5, 2,3,4,5,6, 3,4,5,6,7};
// //arr数组名是首元素地址
// Printf(arr,3,5);
// return 0;
// }
//一维数组传参,形参的部分可以是数组,也可以是指针
// void test1(int arr[5],int sz)
// {
// }
// void test2(int* p,int sz)
// {
// }
// int main()
// {
// int arr[5] = {0};
// test1(arr,5);
// test2(arr,5);
// return 0;
// }
//二维数组传参,形参的部分可以数组,也可以是指针
void test3(char arr[3][5],int r,int c)
{
}
void test4(char(*p)[5],int r,int c)
{
}
int main()
{
char arr[3][5] = {0};
test3(arr,4,5);
test4(arr,3,5);
return 0;
}
指针数组
整型数组-存放整型的数组
字符数组-存放字符的数组
指针数组-存放指针的数组
// int main()
// {
// int* arr[10];//存放整型指针的数组
// char* arr2[10]; //一级字符指针的数组
// char **arr3[10];//二级字符指针的数组
// return 0;
// }
//使用指针数组模拟实现二维数组
int main()
{
int arr1[] = {1,2,3,4,5};
int arr2[] = {2,3,4,5,6};
int arr3[] = {3,4,5,6,7};
//指针数组
int* arr4[3] = {arr1,arr2,arr3};
printf("%d\n",arr4[1][1]);
int i = 0;
for ( i = 0; i < 3; i++)
{
/* code */
int j = 0;
for(j=0;j<5;j++)
{
printf("%d ",arr4[i][j]);
//printf("%d ",*(arr4+i));
}
printf("\n");
}
return 0;
}
在写代码的时候难免要把数组或者指针传给函数,那函数的参数该如何设计呢?
一维数组传参
二维数组传参
一级指针传参
二级指针传参
//二维数组传参,形参是二维数组的形式
// void Printf(int arr[3][5],int r,int c)
// {
// int i = 0;
// for (i = 0; i<3;i++)
// {
// int j = 0;
// for(j = 0;j < 5;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};
// Printf(arr,3,5);
// return 0;
// }
//二维数组传参,形参是指针的形式
// void Printf(int (*p)[5],int r,int c)
// {
// int i = 0;
// for(i = 0; i < r; i++)
// {
// int j = 0;
// for (j = 0; j < c; j++)
// {
// printf("%d ",*(*(p+i)+j));
// }
// }
// }
// //二维数组的每一行可以理解为二维数组的一个元素
// //每一行又是一个一维数组
// //二维数组其实是一维数组的数组
// //二维数组的数组名,也是数组名,数组名就是数组首元素地址
// //arr - 首元素地址 - 第一行的地址 -一维数组的地址 -数组的地址
// int main()
// {
// int arr[3][5] = {1,2,3,4,5, 2,3,4,5,6, 3,4,5,6,7};
// //arr数组名是首元素地址
// Printf(arr,3,5);
// return 0;
// }
//一维数组传参,形参的部分可以是数组,也可以是指针
// void test1(int arr[5],int sz)
// {
// }
// void test2(int* p,int sz)
// {
// }
// int main()
// {
// int arr[5] = {0};
// test1(arr,5);
// test2(arr,5);
// return 0;
// }
//二维数组传参,形参的部分可以数组,也可以是指针
// void test3(char arr[3][5],int r,int c)
// {
// }
// void test4(char(*p)[5],int r,int c)
// {
// }
// int main()
// {
// char arr[3][5] = {0};
// test3(arr,4,5);
// test4(arr,3,5);
// return 0;
// }
//一维数组传参
// void test(int arr[]) //true
// {}
// void test(int arr[10]) //true
// {}
// void test(int* arr) //true
// {}
// void test2(int* arr[20]) //true
// {}
// void test2(int** arr)
// {}
// int main()
// {
// int arr[10] = {0}; //存放整型
// int *arr2[20] = {0}; //存放地址
// test(arr);
// test2(arr2);
// }
//一级指针传参
// void print(int* p,int sz)
// {
// int i = 0;
// for(i = 0;i
函数指针-指向函数的指针
数组指针-指向函数的指针
//函数指针
// int Add(int x,int y)
// {
// return x+y;
// }
// int main()
// {
// int arr[10] = {0};
// int (*pa)[10] = &arr;
// // //&arr;
// // printf("%p\n",&Add);
// // printf("%p\n",Add);
// //函数名是函数的地址
// //&函数名也是函数的地址
// int (*pf)(int,int) =&Add; //pf是函数指针变量 int(*)(int int)是函数指针类型
// }
// void test(char* pc,int arr[10])
// {}
// int main()
// {
// void (*pf)(char*,int[10]) = &test;
// return 0;
// }
int Add(int x,int y)
{
return x+y;
}
int main()
{
//int (*pf)(int,int) = &Add;
int (*pf)(int,int) = Add;
int r = Add(3,5);
printf("%d\n",r);
int m = (*pf)(4,5);
printf("%d\n",m);
return 0;
}
//void (*p)() -p是函数指针
//void (*)()是函数指针类型
// int main()
// {
// //调用0地址处的函数
// //1.将0强制类型转换为void(*)() 类型的函数指针
// //2.调用0地址处的这个函数
// ( *( void (*)())0)();
// }
// typedef unsigned int uint;
// typedef int* ptr_t;
// //typedef int(*)[10] parr_t; //err
// typedef int(*parr_t)[10] ; //true
// typedef int (*pf_t)(int,int);
// int main()
// {
// uint u1;
// ptr_t p1;
// int* p2;
// //parr_t[10];
// //pf_t(2,3);
// return 0;
// }
int main()
{
//signal是一个函数声明
//signal函数有2个参数,第一个参数是int,第二个参数类型是void(*)(int) 函数指针类型
//该函数指针指向的函数有一个int类型的参数,返回类型是void
//signal 函数的返回类型也是 void(*)(int) ,该函数指针指向的函数有一个int类型的参数,返回类型是void
typedef void(*pf_t)(int);
pf_t signal(int ,pf_t);
void (* signal(int,void(*)(int)))(int);
return 0;
}