指針初步:
#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$
函數的參數由右向左入棧
函數變量從棧底(高位址)向棧頂(低位址)遞減