天天看點

C 指針

指針初步:

#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$      

函數的參數由右向左入棧

函數變量從棧底(高位址)向棧頂(低位址)遞減

上一篇: c指針
下一篇: 寫在前面