指针初步:

#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(intaintb)

{

    if (a > b)

       returna;

    else

       returnb;

}

 

int add(intaintb)

{

    returna + b;

}

 

void func(int(*p)(intint), intaintb)

{

    int res =  p(ab);

    printf("%d\n", res);

 

}

 

int  main()

{

    int  i = 0;

    scanf("%d", &i);

    if (i ==  0)

       func(max, 1020);

    else

       func(add, 1020);

    return0;

}

 

 

 

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$





函数的参数由右向左入栈

函数变量从栈底(高地址)向栈顶(低地址)递减