指针初步:
#include <stdio.h>
int main()
{
int i = 10;
int *p1 = &i;
printf("*p1 = %d \n",*p1);
}
root@ubuntu:~/pointer# gcc main.c ;./a.out
*p1 = 10
#include <stdio.h>
int main()
{
int i = 10;
int *p1 = NULL;
p1 = &i;
printf("*p1 = %d \n",*p1);
}
root@ubuntu:~/pointer# gcc main.c ;./a.out
*p1 = 10
#include <stdio.h>
int main()
{
int i = 10;
int *p1 = NULL;
p1 = &i;
*p1 = 20;
printf("*p1 = %d \n",*p1);
}
root@ubuntu:~/pointer# gcc main.c ;./a.out
*p1 = 20
野指针
#include <stdio.h>
int main()
{
int *p3 ; //未初始化的指针,野指针,
*p3 = 10; //gcc 编译不通过:Segmentation fault (core dumped)
}
root@ubuntu:~/pointer# gcc main.c
Segmentation fault (core dumped)
空指针类型,强转指针
#include <stdio.h>
int main()
{
int i = 10;
void *p;
p = &i;
printf("*p = %d\n",*(int *)p);
// (int *)p 把p强转为 int 类型的指针
}
root@ubuntu:~/pointer# gcc main.c ;./a.out
*p = 10
指针类型兼容,不兼容
#include <stdio.h>
int main()
{
int *p = NULL;
unsigned i ;
p = &i;
char c = 'a';
p = &c;
}
main.c:8:11: warning: assignment from incompatible pointer type [enabled by default]
p = &c;
^
数组的地址
#include <stdio.h>
int main()
{
int chunli[10] = {0};
printf("%p\n",chunli);
printf("%p\n",&chunli);
printf("%p\n",&chunli[0]);
printf("%p\n",&chunli[1]);
}
数组的名字就是数组的初始地址;
root@ubuntu:~/pointer# gcc main.c ;./a.out
0x7fffc53060c0
0x7fffc53060c0
0x7fffc53060c0
0x7fffc53060c4
#include <stdio.h>
int main()
{
int chunli[10] = {2};
int *p1 = &chunli[0];
int *p2 = chunli;
printf("%d \n",*p1);
printf("%d \n",*p2);
}
p1 ,p2 指向的是同一个地址
root@ubuntu:~/pointer# gcc main.c ;./a.out
2
2
指针与数组1
#include <stdio.h>
int main()
{
int chunli[10] = {2};
int *p1 = chunli;
printf("sizeof(chunli) =%ld \n",sizeof(chunli));
printf("sizeof(p1) =%ld \n",sizeof(p1));
}
// 32bit系统 一个指针占用4个字节
// 64bit系统 一个指针占用8个字节
root@ubuntu:~/pointer# gcc main.c ;./a.out
sizeof(chunli) =40
sizeof(p1) =8
指针与数组 面试题
#include <stdio.h>
int main()
{
int chunli[10] = {1,2,3};
printf("%p,%d,%p \n",chunli,*chunli,&chunli);
}
chunli@ubuntu:~/pointer$ gcc main.c ;./a.out
0x7ffe2f696310,1,0x7ffe2f696310
指针与数组,指针在数组中移动
#include <stdio.h>
int main()
{
int chunli[10] = {1,2,3};
int *p1 = chunli; //指向数组的首地址
//int *p2 = &chunli; gcc 会报错
printf("%p,%d\n",p1, *p1);
printf("%p,%d\n",p1+1,*p1+1);
printf("%p,%d\n",p1+2,*p1+2);
}
chunli@ubuntu:~/pointer$ gcc main.c ;./a.out
0x7fff5103f740,1
0x7fff5103f744,2
0x7fff5103f748,3
系统的小端对齐方式,由CPU决定!
int类型数据 在内存的存放
chunli@pc0003:~/C_language$ vim main.c
#include <stdio.h>
int main()
{
int i = 15;
char *p = (char *)&i;
printf("int 的第1个字节 %x\n",*(p+0));
printf("int 的第2个字节 %x\n",*(p+1));
printf("int 的第3个字节 %x\n",*(p+2));
printf("int 的第4个字节 %x\n",*(p+3));
}
chunli@pc0003:~/C_language$ gcc main.c ;./a.out
int 的第1个字节 f
int 的第2个字节 0
int 的第3个字节 0
int 的第4个字节 0
再看看16进制的
#include <stdio.h>
int main()
{
int i = 0x12345678;
char *p = (char *)&i;
printf("int 15 的第1个字节 %x\n",*(p+0));
printf("int 15 的第2个字节 %x\n",*(p+1));
printf("int 15 的第3个字节 %x\n",*(p+2));
printf("int 15 的第4个字节 %x\n",*(p+3));
}
chunli@ubuntu:~/pointer$ gcc main.c ;./a.out
int 的第1个字节 78
int 的第2个字节 56
int 的第3个字节 34
int 的第4个字节 12
指针的使用--给数组赋值 scanf
#include <stdio.h>
int main()
{
int myarr[10] ={0} ;
int i=0;
int *p=myarr;
for(i=0;i<10;i++)
{
scanf("%d",p++);
}
for(i=0;i<10;i++)
{
printf("arr[%d] = %d \n",i,myarr[i]);
}
}
chunli@ubuntu:~/pointer$ gcc main.c ;./a.out
1
2
3
4
4
5
6
7
8
8
arr[0] = 1
arr[1] = 2
arr[2] = 3
arr[3] = 4
arr[4] = 4
arr[5] = 5
arr[6] = 6
arr[7] = 7
arr[8] = 8
arr[9] = 8
使用指针输出数组
#include <stdio.h>
int main()
{
int myarr[10] ={1,4,5,2,3,4,8,9} ;
int i=0;
int *p=myarr;
for(i=0;i<10;i++)
{
printf("arr[%d] = %d \n",i,*p++);//*p++自右向左结合运算
}
}
chunli@ubuntu:~/pointer$ gcc main.c ;./a.out
arr[0] = 1
arr[1] = 4
arr[2] = 5
arr[3] = 2
arr[4] = 3
arr[5] = 4
arr[6] = 8
arr[7] = 9
arr[8] = 0
arr[9] = 0
把指针名字当数组使用
#include <stdio.h>
int main()
{
int myarr[10] ={1,4,5,2,3,4,8,9} ;
int i=0;
int *p=myarr;
for(i=0;i<10;i++)
{
printf("arr[%d] = %d \n",i,p[i]); //p[i]等同于*(p+i)
}
}
chunli@ubuntu:~/pointer$ gcc main.c ;./a.out
arr[0] = 1
arr[1] = 4
arr[2] = 5
arr[3] = 2
arr[4] = 3
arr[5] = 4
arr[6] = 8
arr[7] = 9
arr[8] = 0
arr[9] = 0
*(p++) 取下一个地址值
(*p)++ 把值取出来加1
数组 指针 面试题
#include <stdio.h>
int main()
{
//指针数组,10个全是指针
char *p1[10];
p1[0] = "Hello";
p1[1] = "World";
p1+1;
printf("%ld \n",sizeof(p1));
//数组指针,一个指针指向了数组的首地址
char (*p2)[10][10];
printf("%ld \n",sizeof(p2));
}
64位操作系统,一个指针占8位
32位操作系统,一个指针占4位
chunli@ubuntu:~/pointer$ gcc main.c ;./a.out
80
8
二级指针、多级指针:
#include <stdio.h>
int main()
{
int i = 10;
int *p1 = &i;
int **p2 = &p1;
int ***p3 = &p2;
int ****p4 = &p3;
printf(" *p1 =%d \n",*p1);
printf(" **p2 =%d \n",**p2);
printf(" ***p3 =%d \n",***p3);
printf(" ****p4 =%d \n",****p4);
//**p2 = 100;
// *p2 就等于&p1 ,p1的地址;
// **p2 =* 代表的是pa1的地址;
//printf("%d \n",**p2);
}
chunli@ubuntu:~/pointer$ gcc main.c ;./a.out
*p1 =10
**p2 =10
***p3 =10
****p4 =10
指针数据交换
#include <stdio.h>
int main()
{
void swap(int *a,int *b)
{
int i ;
i = *a;
*a = *b;
*b = i;
}
int x,y;
printf("Enter two int number !\n");
scanf("%d %d",&x,&y);
printf("x= %d ,y =%d\n",x,y);
swap(&x,&y);
printf("x= %d ,y =%d\n",x,y);
}
chunli@ubuntu:~/pointer$ gcc main.c ;./a.out
Enter two int number !
12
67
x= 12 ,y =67
x= 67 ,y =12
面试:
不需第三变量 据交换:
#include <stdio.h>
int main()
{
void swap(int *a,int *b)
{
*a = *a ^ *b;
*b = *a ^ *b;
*a = *a ^ *b;
}
int x,y;
printf("Enter two int number !\n");
scanf("%d %d",&x,&y);
printf("x= %d ,y =%d\n",x,y);
swap(&x,&y);
printf("x= %d ,y =%d\n",x,y);
}
chunli@ubuntu:~/pointer$ gcc main.c ;./a.out
Enter two int number !
12 34
x= 12 ,y =34
x= 34 ,y =12
用指针修改地址的方法,函数对数组排序,
#include <stdio.h>
void swap(int *a,int *b)
{
*a = *a ^ *b;
*b = *a ^ *b;
*a = *a ^ *b;
}
void func(int myarray[])
{
for(int i = 0;i<10;i++)
{
for(int j=0;j<10-i-1;j++)
{
if(myarray[j] > myarray[j+1])
{
swap(&myarray[j],&myarray[j+1]);
}
}
}
}
int main()
{
int array[10] ={1,3,7,4,5,6,0,12,56,43} ;
func(array); //把数组名作为地址传过去
for(int i=0;i<10;i++)
{
printf("%d \n",array[i]);
}
}
chunli@ubuntu:~/pointer$ gcc -std=c99 main.c && ./a.out
0
1
3
4
5
6
7
12
43
56
chunli@ubuntu:~/pointer$
用函数修改数组指定位置的数据
#include <stdio.h>
int mod(int *p)
{
*(p+4) = 100;
}
int main()
{
int array[10] ={1,3,7,4,5,6,0,12,56,43} ;
mod(array);
for(int i=0;i<10;i++)
{
printf("%d \n",array[i]);
}
printf("***********************\n");
mod(array + 2); //把第2个
for(int i=0;i<10;i++)
{
printf("%d \n",array[i]);
}
}
chunli@ubuntu:~/pointer$ gcc -std=c99 main.c && ./a.out
1
3
7
4
100
6
0
12
56
43
***********************
1
3
7
4
100
6
100
12
56
43
指针面试题
#include <stdio.h>
int main()
{
printf("sizeof(char) = %ld \n",sizeof(char));
printf("sizeof(char *) = %ld \n",sizeof(char *));
printf("sizeof(int) = %ld \n",sizeof(int));
printf("sizeof(int *) = %ld \n",sizeof(int *));
printf("sizeof(long) = %ld \n",sizeof(long));
printf("sizeof(long *) = %ld \n",sizeof(long *));
char buf[10];
printf("char buf[10] = %ld \n",sizeof(buf ));
char *s[10];//指针的数组
printf("char *s[10] = %ld \n",sizeof(s));
char (*c)[10];//数组的指针
printf("char (*c)[10] = %ld \n",sizeof(c));
}
chunli@ubuntu:~/pointer$ gcc main.c && ./a.out
sizeof(char) = 1
sizeof(char *) = 8
sizeof(int) = 4
sizeof(int *) = 8
sizeof(long) = 8
sizeof(long *) = 8
char buf[10] = 10
char *s[10] = 80
char (*c)[10] = 8
#include <stdio.h>
int main()
{
int arr[10]={4,5,6,7,8};
//arr + =3; 这是一个错误的语法,因为数组的名称是常量
int *p = arr;
printf("%d \n",p[3]); // 指针下标,返回数组第4个具体的值
printf("%d \n",*(p+3)); // 指针位置,返回数组第4个具体的值
int *s1[100]; //定义了一个数组,数组的100个元素全是int类型指针
//s1++; // 非法语句
int (*s2)[100][100];//定义了一个指针,指向了int [100][100]这样的数据空间
char *s3;
s3++; //移动了1个字节
int *s4;
s4++; //移动了4个字节
}
chunli@ubuntu:~/pointer$ gcc main.c && ./a.out
7
7
*星号是从指针变量的值去
#include <stdio.h>
int main()
{
int a = 10;
int *p = &a;
printf("%d\n",*p); // *p直接操作&变量的值
*p =11;
printf("%d\n",*p);
}
chunli@Linux:~/high$ gcc 123.c && ./a.out
10
11
chunli@Linux:~/high$
#include <stdio.h>
int main()
{
int *p0 = NULL;
int **p1 = &p0;
int ***p2 = &p1;
p0 = (int *)&p2;
printf("***p2 = %x \n",***p2);
printf("p0 address=%p \n",&p0);
printf("p1 address=%p \n",&p1);
printf("p2 address=%p \n",&p2);
}
root@ubuntu:~/pointer# gcc main.c && ./a.out
***p2 = 73442910
p0 address=0x7fff73442908
p1 address=0x7fff73442910
p2 address=0x7fff73442918
#include <stdio.h>
int main()
{
int *p1 = NULL;
int **p2 = &p1;
int ***p3 = &p2;
int ****p4 = &p3;
int *****p5 = &p4;
int ******p6 = &p5;
p1 = (int *)&p6;
printf("******p6 = %x \n",******p6);
printf("p1 address=%p \n",&p1);
printf("p2 address=%p \n",&p2);
printf("p3 address=%p \n",&p3);
printf("p4 address=%p \n",&p4);
printf("p5 address=%p \n",&p5);
printf("p6 address=%p \n",&p6);
}
chunli@Linux:~/high$ gcc 123.c && ./a.out
******p6 = 7ee14bf0
p1 address=0x7ffe7ee14bd0
p2 address=0x7ffe7ee14bd8
p3 address=0x7ffe7ee14be0
p4 address=0x7ffe7ee14be8
p5 address=0x7ffe7ee14bf0
p6 address=0x7ffe7ee14bf8
chunli@Linux:~/high$
把数组传到函数
#include <stdio.h>
//这三种描述的是一样的
void fun(int *arr,int len) //数组通过函数形参传递时,无法传递数组的大小
//void fun(int arr[1],int len) //无法传递数组的大小,并不认为这是一个大小为 1的数组
//void fun(int arr[],int len)
{
for(int i=0;i<len;i++)
{
printf("%d\n",*(arr+i));
}
}
int main()
{
int n[17] = {12,2,4,6};
fun(n,sizeof(n)/sizeof(int));//把数组名,数组的大小传过去
}
root@ubuntu:~/pointer# gcc -std=c99 main.c && ./a.out
12
2
4
6
0
0
0
0
0
0
0
0
0
0
0
0
0
数组地址
#include <stdio.h>
int main()
{
int arr[3][4] = {{0,1,2,3},{4,5,6,7},{8,9,10,11}};
printf(" %p\n %p\n %p\n %p\n %p\n",arr,*arr,&arr,&arr[0],&arr[0][0]);
//在一维数组中,*数组名就是第一个数组的值
}
root@ubuntu:~/pointer# gcc -std=c99 main.c && ./a.out
0x7ffd2163f9f0
0x7ffd2163f9f0
0x7ffd2163f9f0
0x7ffd2163f9f0
0x7ffd2163f9f0
二维数组与指针1
#include <stdio.h>
int main()
{
int arr[3][4] = {{0,1,2,3},{4,5,6,7},{8,9,10,11}};
printf(" %p\n %p\n %p\n %p\n %p\n",arr,*arr,&arr,&arr[0],&arr[0][0]);
//在一维数组中,*数组名就是第一个数组的值
printf(" %p \n",arr + 1);
printf(" %p \n",arr[0] + 1);
}
arr + 1 :一次移动一排
arr[0] + 1 :一次移动一个
root@ubuntu:~/pointer# gcc -std=c99 main.c && ./a.out
0x7ffcbd4da550
0x7ffcbd4da550
0x7ffcbd4da550
0x7ffcbd4da550
0x7ffcbd4da550
0x7ffcbd4da560
0x7ffcbd4da554
二维数组与指针2,很难理解!
#include <stdio.h>
int main()
{
int arr[3][4] = {{0,1,2,3},{4,5,6,7},{8,9,10,11}};
int (*p)[4]; //变相二维数组的指针,可以理解为*p就是指针名,**P才是取值
p = arr;
printf("%d \n",*((*p)+1));
printf("%d \n",*(*p)+1);
printf("%d \n",**p+1);
}
root@ubuntu:~/pointer# gcc -std=c99 main.c && ./a.out
1
1
1
指针输出二维数组
#include <stdio.h>
int main()
{
int arr[3][4] = {{0,1,2,3},{4,5,6,7},{8,9,10,11}};
int (*p)[4]; //变相二维数组的指针,**P才是取数组的值
p = arr;
//*(*(p+0)+1) 代表int * 向后移了一个位置
//printf("%d \n",*(*(p+1)+1)); //输出第一行的第2个数值
for(int i=0;i<3;i++)
{
for(int j=0;j<4;j++ )
{
printf("%d\t",*(*(p+i)+j));
}
printf("\n");
}
}
root@ubuntu:~/pointer# gcc -std=c99 main.c && ./a.out
0 1 2 3
4 5 6 7
8 9 10 11
指针转置输出二维数组
#include <stdio.h>
int main()
{
int arr[3][4] = {{0,1,2,3},{4,5,6,7},{8,9,10,11}};
int (*p)[4]; //变相二维数组的指针,**P才是取数组的值
p = arr;
//*(*(p+0)+1) 代表int * 向后移了一个位置
//printf("%d \n",*(*(p+1)+1)); //输出第一行的第2个数值
for(int i=0;i<4;i++)
{
for(int j=0;j<3;j++ )
{
printf("%d\t",*(*(p+j)+i));
}
printf("\n");
}
}
root@ubuntu:~/pointer# gcc -std=c99 main.c && ./a.out
0 4 8
1 5 9
2 6 10
3 7 11
二维数组与指针3
#include <stdio.h>
int main()
{
int arr[3][4] = {{0,1,2,3},{4,5,6,7},{8,9,10,11}};
int (*p)[4]; //变相二维数组的指针,**P才是取数组的值
p = arr;
//*(*(p+0)+1) 代表int * 向后移了一个位置
printf("%d \n",*(*(p+1)+1)); //输出第一行的第2个数值
//*(*(p+1)+1)) : (p+1) 一次连续移动int (*p)[4] 16个字节
}
root@ubuntu:~/pointer# gcc -std=c99 main.c && ./a.out
5
函数打印二维数组
#include <stdio.h>
void fun(int p[][4],int a,int b)
{
for(int i=0;i<a;i++)
{
for(int j =0;j<b;j++)
{
printf("%d\t",*(*(p+i)+j));
}
printf("\n");
}
}
int main()
{
int arr[3][4] = {{0,1,2,3},{4,5,6,7},{8,9,10,11}};
//fun(arr,行,列);
fun(arr,sizeof(arr)/sizeof(arr[0]),sizeof(arr[0])/sizeof(int));
}
root@ubuntu:~/pointer# gcc -std=c99 main.c && ./a.out
0 1 2 3
4 5 6 7
8 9 10 11
#include <stdio.h>
int main()
{
//指向常量的指针
int i = 10;
const int *p1 = &i; //定义一个指针,指向一个常量,通过指针无法修改所指向变量的值
//*p =100; //这个语句无法通过编译
//通过指向常量的指针,可以限制指针修改变量的值
//虽然无法修改变量的值,但是可以乱指
//指针常量
int *const p2 = &i;//定义一个指针的常量,这个指针就只能指向这个变量,不能再指向其他的变量
int j = 20;
//*p2 = &j; //这条语句不会通过,因为这个指针无法指向其他的变量
}
#include <stdio.h>
void fun(const int *p,int n) //不希望通过指针修改变量的值
{
for(int i=0;i<n;i++)
{
//printf("%d \n",p[i]);
printf("%d \n",*p++);//两种方式是一样的
}
}
int main()
{
int arr[] = {2,4,5,654,545,1,7};
printf("%p \n",fun);// 函数也有地址
fun(arr,sizeof(arr)/sizeof(int));
}
chunli@ubuntu:~/pointer$ gcc -std=c99 main.c && ./a.out
0x40052d
2
4
5
654
545
1
7
函数指针的定于使用
#include <stdio.h>
void fun(int n)
{
printf("fun %d\n",n);
}
int main()
{
void (*p)(int);//定义一个指针,指向有一个int参数,返回值为void的函数指针
p = fun; //让p指向fun函数的入口地址
p(10); //执行函数
}
chunli@ubuntu:~/pointer$ gcc -std=c99 main.c && ./a.out
fun 10
函数指针---回调函数
#include <stdio.h>
void fun(int n)
{
printf("fun %d\n",n);
}
int myadd(int a,int b)
{
return a + b;
}
int mysub(int a,int b)
{
return a - b;
}
int pointer_fun(int (*p)(int ,int),int a,int b)
{
return p(a,b);
}
int main()
{
int i = pointer_fun(myadd,4,5);
fun(i);
i = pointer_fun(mysub,4,5);
fun(i);
}
chunli@ubuntu:~/pointer$ gcc -std=c99 main.c && ./a.out
fun 9
fun -1
#include <stdio.h>
int main()
{
char s[] = "Hello World!";
char *p = s;
p[2] = 'a';
printf("%s \n",s);
}
chunli@ubuntu:~/pointer$ gcc main.c && ./a.out
Healo World!
#include <stdio.h>
int main()
{
char *p = "Hello World!";
p[2] = 'a';
printf("%s \n",s);
}
编译报错!
因为 char *p = "Hello World!"; 指向的是字符串常量,只读!
字符串指针
#include <stdio.h>
fun(char *p)
{
p[3] = 'a';
}
int main()
{
char s[] = "Hello World!";
fun(s);
printf("%s \n",s);
}
chunli@ubuntu:~/pointer$ gcc main.c && ./a.out
Helao World!
自己实现strcopy功能;
#include <stdio.h>
void fun(char *p1,const char *p2)
{
int i=0;
while(p2[i] != '\0'){
p1[i] = p2[i];
i++;
}
}
int main()
{
char buf[100] = {0};
fun(buf,"Hello World!");
printf("%s \n",buf);
}
chunli@ubuntu:~/pointer$ gcc main.c && ./a.out
Hello World!
代码优化:
#include <stdio.h>
void fun(char *p1,const char *p2)
{
while(*p1++ = *p2++);
//当*p2 == 0的时候就停止了
}
int main()
{
char buf[100] = "AAAAAAAAAAAAAAAAAAAAAAA";
fun(buf,"Hello World!");
printf("%s \n",buf);
}
chunli@ubuntu:~/pointer$ gcc main.c && ./a.out
Hello World!
strncpy的自定义版本:
#include <stdio.h>
void fun(char *p1,const char *p2,int n)
{
while(n--)
{
*p1++ = *p2++;
}
*(p1) = '\0';
//*(p1-1) = '\0';
}
int main()
{
char buf[100] = "AAAAAAAAAAAAAAAAAAAAAAA";
fun(buf,"Hello World!",3);
printf("%s \n",buf);
}
chunli@ubuntu:~/pointer$ gcc main.c && ./a.out
Hel
字符编码长度
#include <stdio.h>
#include <string.h>
int main()
{
char *p = "UTF8编码";
printf("%ld \n",strlen(p));
}
chunli@ubuntu:~/pointer$ gcc main.c && ./a.out
10
计算UTF编码编码的字符串长度
#include <stdio.h>
int mystrlen(const char *p)
{
int num = 0;
while(*p)
{
num++;
if(*p++<0)
{
p++;
p++;
}
}
return num;
}
int main()
{
char *p = "UTF8编码";
printf("%d \n",mystrlen(p));
}
chunli@ubuntu:~/pointer$ gcc main.c && ./a.out
6
字符串指针,实现strcmp
#include <stdio.h>
int mystrcmp(const char *p1, const char *p2)
{
int result = 1;
while( *p1 && *p2 )
{
while(*p1++ != *p2++)
{
result = 0;
}
}
return result;
}
int main()
{
char c1[] = "UTF8编码";
char c2[] = "GBK编码";
printf("%d \n",mystrcmp(c1, c2));
}
有一个bug,当两个字符串前面完全一样时,后面的细微变化导致bug
chunli@ubuntu:~/pointer$ gcc main.c && ./a.out
0
指针实现字符串分割
#include <stdio.h>
char *mystrtok(char *s, int n)
{
while(1)
{
if (n == 1)
return s;
if (*s++ == ' ')
n--;
}
}
int main()
{
char c[] = "UTF8 编 123码";
printf("%s \n",mystrtok(c,2));
printf("%s \n",c);
}
chunli@ubuntu:~/pointer$ gcc main.c && ./a.out
编 123码
UTF8 编 123码
数字转字符,支持负数
#include <stdio.h>
int caluintlen(unsigned int n)
{
int result = 1;
while (n /= 10)
{
result++;
}
return result;
}
int calnumlen(int i)
{
int result = i < 0 ? 1 : 0;
result += caluintlen(i < 0 ? -i : i);
return result;
}
void myitoa(int i, char *s)
{
int count = calnumlen(i);
if (i<0)
{
*s = '-';
i = -i;
}
s += count;//指向了要转化后的字符串的最后
*s = 0;//字符串结尾赋值0,
while (i > 0)
{
*--s = (i % 10) + 0x30;
i /= 10;
}
}
int main()
{
char buf[100] = { 0 };
myitoa(23412, buf);
printf("%s \n",buf);
return 0;
}
chunli@ubuntu:~/pointer$ gcc main.c && ./a.out
23412
main函数的参数
#include <stdio.h>
int main(int argc,char **args) //二级指针
//int main(int argc,char *args[]) //等效上
{
for(int i = 0; i< argc; i++)
{
//printf("%s \n",args[i]); //等效下
printf("%s \n",*args++);
}
return 0;
}
chunli@ubuntu:~/pointer$
chunli@ubuntu:~/pointer$ gcc -std=c99 main.c && ./a.out 123 "Hello World!" 您好
./a.out
123
Hello World!
您好
返回字符串
#include <stdio.h>
const char *chunli_getchar()
{
const char *s = "abcd";
return s;
}
/*函数放在代码区 */
int main()
{
printf("%s \n",chunli_getchar());
}
chunli@ubuntu:~/pointer$ gcc -std=c99 main.c && ./a.out
abcd
1.1 指针
1.1.1 指针的概念
指针也是一个变量,做为指针变量的值是另一个变量的地址。
指针存放的内容是一个地址,该地址指向一块内存空间
1.1.2 指针变量的定义
可以定义一个指向一个变量的指针变量。
int *p;//表示定义一个指针变量。
*p;//代表指针所指内存的实际数据
切记,指针变量只能存放地址,不能将一个int型变量直接赋值给一个指针。
int *p = 100;
1.1.3 NULL
一个指向NULL的指针,我们称之为空指针,意味着这个指针不指向任何一个变量。
野指针
1.1.4 &取地址运算符
1.1.5 无类型指针
定义一个指针变量,但不指定它指向具体哪种数据类型。可以通过强制转化将void *转化为其他类型指针,也可以用(void*)将其他类型指针强制转化为void类型指针。
void *p
在C语言当中,可以将任何一种地址赋值给void *指针
1.1.6 指针的兼容性
指针之间赋值比普通数据类型赋值检查更为严格,例如:不可以把一个double *赋值给int *
1.1.7 指针与数组的关系
一个变量有地址,一个数组包含若干个元素,每个元素在内存中都有地址。
int a[10];
int *p = a;
比较p和&a[0]的地址是否相同
在C语言当中数组的名称代表数组的首地址,如果取数组名称的地址,C语言认为就是取数组的首地址。
1.1.8 通过指针使用数组元素
通过指针计算,不是把指针当做一个整数,计算结果,而是指针在内存当中移动
p + 1代表&a[1],也可以直接使用p[1]表示a[5]
p + 5 代表&a[5]
p++
在C语言里面数组名称是个常量,值是不可改变的
1.1.9 指针数组
int *p[5];
1.1.10 数组指针
int (*P)[5];
1.1.11 指向指针的指针(二级指针)
指针就是一个变量,既然是变量就也存在内存地址,所以可以定义一个指向指针的指针。
inti=10;
int*p1=&i;
int**p2=&p1;
printf("%d\n",**p2);
以此类推可以定义3级甚至多级指针。
1.1.12 指针变量做为函数的参数
函数的参数可以是指针类型。,它的作用是将一个变量的地址传送给另一个函数。
1.1.13 一维数组名作为函数参数
当数组名作为函数参数时,C语言将数组名解释为指针
当数组名作为函数参数传递给被调用函数时,被调用函数是不知道数组有多少元素的
int func(int array[10]);
相当于传递是一个地址,那么就可以通过地址来修改实参的值。
只要传递是数组名,那么形参一定可以通过地址修改实参的值。
1.1.14 二维数组名作为函数参数
二维数组做函数参数时可以不指定第一个下标。
int func(int array[][10]);
1.1.15 指向二维数组的指针
int a[3][5]
a | 二维数组名称,数组首地址 |
a[0], *(a + 0), *a | 0行,0列元素地址 |
a + 1 | 第1行首地址 |
a[1], *(a + 1) | 第1行,0列元素地址 |
a[1] + 2, *(a + 1) + 2, &a[1][2] | 第1行,2列元素地址 |
*(a[1] + 2), *(*(a + 1) + 2), a[1][2] | 第1行,2列元素的值 |
1.1.16 指向常量的指针与指针常量
const char *p;//定义一个指向常量的指针
char *const p;//定义一个指针常量,一旦初始化之后其内容不可改变
1.1.17 const关键字保护数组内容
如果将一个数组做为函数的形参传递,那么数组内容可以在被调用函数内部修改,有时候不希望这样的事情发生,所以要对形参采用const参数
func(const int array[])
1.1.18 指针做为函数的返回值
char *func();//返回值为char *类型的函数
1.1.19 指向函数的指针
指针可以指向变量,数组,也可以指向一个函数。
一个函数在编译的时候会分配一个入口地址,这个入口地址就是函数的指针,函数名称就代表函数的入口地址。
函数指针的定义方式:int(*p)(int);//定义了一个指向int func(int n)类型函数地址的指针。
1定义函数指针变量的形式为:函数返回类型(*指针变量名称)(参数列表)
2函数可以通过函数指针调用
3int( * P)()代表指向一个函数,但不是固定哪一个函数。
void man() { printf("抽烟\n"); printf("喝酒\n"); printf("打牌\n"); } void woman() printf("化妆\n"); printf("逛街\n"); printf("网购\n"); int main() void(*p)(); int i = 0; scanf("%d", &i); if (i == 0) p = man; else p = woman; p(); return0; |
1.1.20 把指向函数的指针做为函数的参数
将函数指针做为另一个函数的参数称为回调函数
int max(inta, intb) if (a > b) returna; returnb; int add(inta, intb) returna + b; void func(int(*p)(int, int), inta, intb) int res = p(a, b); printf("%d\n", res); int i = 0; func(max, 10, 20); func(add, 10, 20); |
1.1.21 指针运算
赋值:int*p = &a;
求值:int I= *p;
取指针地址 int**pp = &p;
将一个整数加(减)给指针:p + 3; p – 3;
增加(减少)指针值p++,p--
求差值 ,p1 –p2,通常用于同一个数组内求两个元素之间的距离
比较 p1== p2,通常用来比较两个指针是否指向同一个位置。
1.1.22 指针小结
定义 | 说明 |
Int i | 定义×××变量 |
int *p | 定义一个指向int的指针变量 |
Int a[10] | 定义一个int数组 |
Int *p[10] | 定义一个指针数组,其中每个数组元素指向一个int型变量的地址 |
Int func() | 定义一个函数,返回值为int型 |
Int *func() | 定义一个函数,返回值为int *型 |
Int (*p)() | 定义一个指向函数的指针,函数的原型为无参数,返回值为int |
Int **p | 定义一个指向int的指针的指针,二级指针 |
2 字符指针与字符串
2.1 指针和字符串
在C语言当中,大多数字符串操作其实就是指针操作。
char s[] = "hello word"; char *p = s; p[0] = 'a'; |
2.2 通过指针访问字符串数组
复习:
指针复习:
1,函数引用外部指针
#include <stdio.h>
#include <stdlib.h>
void fun1(int *p)
{
p = malloc(4);
printf("fun1 %p \n",p);
}
void fun2(int **p)
{
*p = malloc(4);
printf("fun2 %p \n",*p);
}
int main()
{
int *p = NULL;
fun1(p);
printf("main %p \n\n",p);
fun2(&p);
printf("main %p \n",p);
return 0;
}
编译运行:
chunli@ubuntu:~/review$ gcc main.c && ./a.out
fun1 0x176d010
main (nil)
fun2 0x176d030
main 0x176d030
数组、指针复习:
chunli@ubuntu:~/review$ cat main.c
#include <stdio.h>
#include <stdlib.h>
const char *test()
{
return malloc(1);
}
int *test2(int *a) //把传过来的数值当做地址传出去
{
return a+1 ;
}
int main()
{
int a[5][10];
//a[0]= 3; 没有这个变量,无法通过编译
printf("%ld \n",sizeof(a));
printf("%ld \n",sizeof(a[0]));
printf("%ld \n",sizeof(a[0][0]));
printf("二维数组首地址 %p ,%p\n",&a,*(a));
printf("二维数组第1行地址 %p ,%p\n",&a[0],*(a+0));
printf("二维数组第1行第1个元素 %p \n",&a[0][0]);
printf("移动到下一个这么大小的地址 %p \n",&a+1);
printf("移动到二维数组第2行 %p \n",&a[0]+1);
printf("移动到二维数组第1行第2个元素 %p \n",&a[0][0]+1);
a[1][3] = 9;
printf("%d \n",*(*(a+1)+3));
const char *p = test();
int c = 100;
int *b = test2(&c);
printf("%d \n",*b);
int *(*p2)(int *a); //定义一个函数指针p2,参数是int,返回值是int
p2 = test2;
return 0;
}
chunli@ubuntu:~/review$
编译运行:
chunli@ubuntu:~/review$ gcc main.c && ./a.out
200
40
4
二维数组首地址 0x7ffe2c0282b0 ,0x7ffe2c0282b0
二维数组第1行地址 0x7ffe2c0282b0 ,0x7ffe2c0282b0
二维数组第1行第1个元素 0x7ffe2c0282b0
移动到下一个这么大小的地址 0x7ffe2c028378
移动到二维数组第2行 0x7ffe2c0282d8
移动到二维数组第1行第2个元素 0x7ffe2c0282b4
9
8749072
chunli@ubuntu:~/review$
函数的参数由右向左入栈
函数变量从栈底(高地址)向栈顶(低地址)递减