本文記錄了一些C指針的定義,包括空指針、野指針、數(shù)組指針、指針數(shù)組、函數(shù)指針、指針函數(shù)、多級指針等等一些知識點的小結。
參考工程(vs19編寫):代碼下載
沒有賦值的指針變量(沒有指向內存變量的地址),對空指針操作會造成程序的Core dump(段錯誤)
#include <stdio.h>
#include <stdlib.h>
int main()
{
int* p_i = 0;
printf('p_i = %p \r\n', p_i);
*p_i = 2;// 試圖對空指針進行賦值操作,程序會崩潰
return 0;
}
指向的內存被釋放了的指針,但指針的值不會清零。對其操作不可預知。
以下操作均為錯誤操作。
#include <stdio.h>
#include <stdlib.h>
int main()
{
int *p_i = (int *) malloc(sizeof(int));
*p_i = 10;
printf('p_i = %d \r\n',*p_i);
free(p_i);
*p_i = 2;
printf('pi = %d \r\n',*p_i);
return 0;
}
#include <stdio.h>
#include <stdlib.h>
int main()
{
int *p_i = (int *) malloc(sizeof(int));
*p_i = 10;
printf('p_i = %d \r\n',*p_i);
free(p_i);
*p_i = 2;
printf('pi = %d \r\n',*p_i);
FILE *fp=fopen('1.txt','w');
printf('fp is %p\r\n',fp);
fclose(fp);
printf('fp is %p\r\n',fp);
//fclose(fp);
return 0;
}
free ( p );帶上p = 0;避免野指針錯誤。
#include <stdio.h>
#include <stdlib.h>
int main()
{
char* p = (char*)malloc(sizeof(char)*4);
free(p);
p = 0;
strcpy(p,'123');
printf('%s\r\n', p);
return 0;
}
數(shù)組名、數(shù)組地址、數(shù)字首元素地址均為同一地址。
#include <stdio.h>
#include <stdlib.h>
int main()
{
char num[20] = 'hello word';
printf('數(shù)組名 %p \r\n', num);
printf('數(shù)組地址 %p \r\n', &num);
printf('數(shù)組首元素 %p \r\n', &num[0]);
printf('打印以數(shù)組名 %s \r\n', num);
printf('打印以數(shù)組地址 %s \r\n', &num);
printf('打印以數(shù)組首元素 %s \r\n', &num[0]);
return 0;
}
結果:
sizeof(數(shù)組)會得到數(shù)組長度,但是通過函數(shù)傳入數(shù)組的指針sizeof卻是指針的大小。
如果數(shù)組的長度小于指針的大小,會導致程序崩潰,如下代碼。不同系統(tǒng)指針大小不一致。
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
void fun(char* p);
int main()
{
char str[3] ;
printf('%d\r\n', sizeof(str));
fun(str);
return 0;
}
void fun(char* p)
{
printf('%d\r\n', sizeof(p));
memset(p, 0, sizeof(p));
scanf('%s',p);
printf('%%p :%p \r\n',p);
printf('%%s :%s \r\n',p);
}
建議:不要在函數(shù)里面調用memset時,使用sizeof計算長度。
補充:結構體用sizeof計算指針也會出錯。
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
struct Student
{
int age;
char name[21];
};
void fun(struct Student* p)
{
printf('in fun() sizeof: %ld\r\n', sizeof(p));// sizeof(struct Student)
memset(p, 0, sizeof(p));// 不建議使用,指清除了指針大小個字節(jié)
// 建議改為下述代碼,使用sizeof(struct Student)
// memset(p, 0, sizeof(struct Student));
}
int main()
{
struct Student stu = { 22,'LiHua' };
printf('in main() sizeof :%ld\r\n', sizeof(stu));
fun(&stu);
return 0;
}
vs19編譯結果:(指針4字節(jié))
虛擬機結果:(指針8字節(jié))
為什么結構體大小28?
因為int 4字節(jié),結構體4字節(jié)對齊,所以為28。
地址可加減運算:+1表示加一個存儲單位的地址,-1減一個存儲單位的地址。
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int main()
{
char cc[4];
int ii[4];
double dd[4];
printf(' char: %p %p %p %p\r\n', cc, cc+1, cc+2, cc+3);
printf(' int: %p %p %p %p\r\n', ii, ii+1, ii+2, ii+3);
printf('double: %p %p %p %p\r\n', dd, dd+1, dd+2, dd+3);
return 0;
}
vs19運行結果:(char + 1,int + 4,double + 8)
同樣的使用地址操作可以直接訪問數(shù)組元素,如*(cc+1)
與cc[1]
等效。
眾所周知,C語言的標準庫沒有字符串截取函數(shù)。為什么?筆者認為可能是沒有必要。因為可以直接地址運算操作地址實現(xiàn)。
字符串截取舉例:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int main()
{
char src[12] = 'hello world';
char dest[10];
memset(dest, 0, 10);
// 將src截取后面world賦值給dest
strncpy(dest,src + 6, 5);// 地址操作
printf('dest:%s\r\n',dest);
return 0;
}
vs19運行結果:
在C里面字符串實際就是以'\0’為結束符的char類型一維數(shù)組,故同樣可以作為一個地址。它的值為字符串的首地址。
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define HD 'hello world'
int main()
{
char *str = 'hello world';
char* str1 = '23333';
printf('HD:%s \r\n', str + 6);
printf('str1:%s\r\n',str1);
return 0;
}
結果:
但因為是常量,所有并不能直接通過str[0] = 'H’來改變字符串的值,使字符串變成“Hello word”。這種做法是錯誤的。
定義:C程序每一個函數(shù)都有一個入口地址,所謂函數(shù)指針就是指向函數(shù)入口地址的指針變量。
應用:調用函數(shù)和做函數(shù)的參數(shù)。
定義格式:
返回值類型 (* 函數(shù)指針)(參數(shù)列表...)
返回值和參數(shù)列表應該和要指向的函數(shù)保持一致。
此外:函數(shù)名也是指針,即fun_max
和&fun_max
等效。
改變指針變量的指向不同的函數(shù),可以實現(xiàn)類似多態(tài)的效果。
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
// 返回最大值
int fun_max(int x, int y)
{
if (x > y) return x;
return y;
}
// 返回最小值
int fun_min(int x, int y)
{
if (x < y) return x;
return y;
}
int main()
{
int a = 2;
int b = 5;
// 定義函數(shù)指針
int (*fun_ptr)(int, int);// 格式要匹配,返回值、參數(shù)及參數(shù)個數(shù)順序都要一致。
fun_ptr = &fun_max; // 函數(shù)名也是指針,與fun_ptr = fun_max;等效
printf('max:%d\r\n', fun_ptr(a,b));
fun_ptr = fun_min;
printf('min:%d\r\n', fun_ptr(a, b));
return 0;
}
運行結果:
max:5
min:2
函數(shù)指針常常和typedef組合使用,更直觀。
如上可以寫為:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
// 格式要匹配,返回值、參數(shù)及參數(shù)個數(shù)順序都要一致。
typedef int (* _fun_ptr_t)(int,int);
// 返回最大值
int fun_max(int x, int y)
{
if (x > y) return x;
return y;
}
// 返回最小值
int fun_min(int x, int y)
{
if (x < y) return x;
return y;
}
int main()
{
int a = 2;
int b = 5;
// 使用typedef定義函數(shù)指針
_fun_ptr_t fun_ptr;
fun_ptr = &fun_max; // 函數(shù)名也是指針,與fun_ptr = fun_max;等效
printf('max:%d\r\n', fun_ptr(a,b));
fun_ptr = fun_min;
printf('min:%d\r\n', fun_ptr(a, b));
return 0;
}
定義:返回值為一個地址的函數(shù)
#include<stdio.h>
char* getword(char);
char* getword(char c)
{
switch (c)
{
case'A':return'Apple';
case'B':return'Banana';
case'C':return'Cat';
case'D':return'Dog';
default:return'None';
}
}
int main()
{
char input;
printf('請輸入一個大寫字母:\n');
scanf('%c', &input);
printf('%s\n', getword(input));
}
測試輸入字母輸出對應字符串
比如:
請輸入一個大寫字母:
C
Cat
指針數(shù)組:
int *p1[10];
解釋:[]的優(yōu)先級比*高,p[10]表示一個大小為10個單位的數(shù)組,int *再來修飾數(shù)組的內容,表示p1數(shù)組為一個存儲10個int型指針的數(shù)組。
數(shù)組指針:指向一個數(shù)組的指針。
int (*p2)[10];
解釋:(*p2)表示一個指針,[10]說明是一個數(shù)組,int修飾數(shù)組元素的類型,綜上就是定義了一個指針p2,它指向有10個int元素數(shù)組的首地址。
無聊。。。。
無聊的一個概念,說白了就是指針指向指針。
舉例代碼:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int main()
{
int i = 2;
int* pi = &i;
int** ppi = π
int*** pppi = &ppi;
printf('%d\r\n', i);
printf('%d\r\n', *pi);
printf('%d\r\n', **ppi);
printf('%d\r\n', ***pppi);
return 0;
}
類似俄羅斯套娃,要是樂意可以一直“取地址”再“解引用”。
運行結果:(說明了這都是2)
2
2
2
2
聯(lián)系客服