指針
數組指針與指針數組
數組指針
定義
概念:數組指針是指向數組的指針,本質上還是指針
特點:
①先有數組,后有指針
②它指向的是一個完整的數組
一維數組指針
語法:
?數據類型 (*指針變量名)[容量];
案例:
?/*int arr[] = {11,22,33,44,55};?int *p = arr;p++;*/??/*************************************************************************> File Name: ? demo01.c> Author: ? ? ? 趙生鑫> Description: ?> Created Time: 2025年03月20日 星期四 09時48分24秒************************************************************************/?#include <stdio.h>?/***數組指針:指向數組的指針(這里指向整個數組,不是數組的某個元素)** */?int main(int argc,char *argv[]){//一維數組指針//先有數組,再有指針//指針不能獨立存在,必須依賴與現有的常量或者變量空間int arr[] = {100,200,300};?//獲取數組大小int len = sizeof(arr) / sizeof(arr[0]);?//指針變量指向數組元素:此時指針指向的時數組中的第一個元素,此時指針存儲的值是首元素的地址值//數組指針指向整個數組:此時指針指向的是整個數組,此時指針存儲的值是首元素的地址值?//定義一個數組指針int (*p)[3] = &arr;//arr默認指向首元素,&arr指向整個數組?//p++ 此時不能p++,否則會越界printf("%p,%p,%p\n",p,&arr,arr);//輸出3個地址相等?//如何訪問數組指針printf("%d\n",(*p)[2]);?//遍歷數組指針for ( int i = 0;i < len ;i++){printf("%-6d",(*p)[i]);//數組指針本質是指針,所以我們需要添加()提升指針優先級(默認數組優先)}printf("\n");return 0;}
我們之前所學的是指向數組元素的指針,本質上是指針變量;現在我們學的是指向數組的指針,叫做數組指針
二維數組指針
語法:
?數據類型 (*指針變量名)[行容量][列容量];
案例:
-
寫法1
?/*************************************************************************> File Name: ? demo02.c> Author: ? ? ? 趙生鑫> Description: ?> Created Time: 2025年03月20日 星期四 10時17分55秒************************************************************************/?#include <stdio.h>?int main(int argc,char *argv[]){int arr[][3] = {11,22,33,44,55,66,77,88,99};?//定義一個數組指針指向二維數組arr//int (*p)[][3] = &arr; ? 數組指針指向二維數組,不推薦int (*p)[3] = arr;//數組指針指向二維數組首行,推薦??//遍歷(數組方式)for(int i = 0; i < 3;i++){for(int j = 0;j < 3;j++){printf("%-6d",p[i][j]);//arr的地址 等于 p存儲的值,也就意味著p等價與arr}printf("\n");}?//p++;//此時是可以使用,因為p指向的是arr中的行,默認為首行return 0;}?
-
寫法2
?/*************************************************************************> File Name: ? demo02.c> Author: ? ? ? 趙生鑫> Description: ?> Created Time: 2025年03月20日 星期四 10時17分55秒************************************************************************/?#include <stdio.h>?int main(int argc,char *argv[]){int arr[][3] = {11,22,33,44,55,66,77,88,99};?//定義一個數組指針指向二維數組arr//int (*p)[][3] = &arr; ? 數組指針指向二維數組,不推薦int (*p)[3] = arr;//數組指針指向二維數組首行,推薦??int rows = sizeof(arr) / sizeof(arr[0]);int cols = sizeof(arr) / sizeof(arr[0]);?for(int i = 0;i < rows;i++){for(int j = 0;j < cols;j++){//三種寫法//1.指針數組語法printf("%-6d",p[i][j]);?//2.指針解引用printf("%-6d",*(*(p + i) + j));?//3.混合法printf("%-6d",(*(p + i))[j]);//解引用符*和數組訪問符[]在一起時,默認的[]優先級高}printf("\n");}??//p++;//此時是可以使用,因為p指向的是arr中的行,默認為首行return 0;}?
指針和數組中的符號優先級
() > [] > *
通過指針引用二維數組
注意:二維數組中,數組整體的地址值 = 數組中0行元素的地址值 = 數組中0行0列元素的地址值
案例
案例1
-
需求:用指向元素的指針變量輸出二維數組元素的值
-
代碼:
?/*************************************************************************> File Name: ? demo03.c> Author: ? ? ? 趙生鑫> Description: ?> Created Time: 2025年03月20日 星期四 11時46分00秒************************************************************************/?#include <stdio.h>?int main(int argc,char *argv[]){//定義一個普通二維數組int arr[3][4] = {10,20,30,40,100,200,300,400,1000,2000,3000,4000};?//定義一個指針變量,用來接收二維數組的元素int *p = arr[0];//0列的位置?//獲取元素個數int len = (sizeof(arr) / sizeof(arr[0])) * (sizeof(arr[0]) / sizeof(arr[0][0]));//遍歷數組for(;p < arr[0]+len;p++){//每4個換行if((p - arr[0]) % 4 == 0)printf("\n");printf("%-6d",*p);}printf("\n");??return 0;}?
??
指針數組
定義:指針數組是一個數組,數組中的每一個元素都是一個指針
特點:
-
先有指針,后有數組
-
指針數組的本質是一個數組,只是數組中的元素類型是指針
語法:
?數據類型 *數組名[容量];
?#include <stdio.h>?int main(){//定義三個變量int a = 10,b = 20,c = 30;//定義指針數組,指針數組是用來存儲指針int *arr[3] = {&a,&b,&c};//獲取數組大小int len = sizeof(arr) / sizeof(arr[0]);//遍歷數組for(int i = 0;i < len; i++){pritnf("%-3d",*arr[i]6);}return 0;}
建議:我們一般使用指針數組處理字符串。
數組指針與指針數組的區別

字符數組和字符指針
字符串實現
再C語言中,表示一個字符串有以下兩種方式:
①數組形式:用字符數組存放一個字符串
②指針形式:用字符指針指向一個字符串
案例
?#include <stdio.h>?/*方式1:使用字符數組實現字符串*/void str_test1(){//定義一個偽字符串char str[] = " I LOVE YOU";printf("%s\n",str);}??/*方式2:使用字符指針實現字符串*/void str_test2(){//定義一個偽字符串char *str = "I LOVE YOU";printf("%s\n",str);}???int main(){str_test1();str_test2();return 0;}
注意:字符數組和字符指針變量都能實現字符串的存儲與運算。(字符指針→字符類型的指針變量)
字符數組和字符指針的聯系
概念
-
字符數組由元素組成,每個元素中存放一個字符,而字符指針變量中存放的是地址(可以作為函數參數)
-
只能對字符數組中的各個元素賦值,而不能用賦值語句對整個字符數組賦值
?char arr[3] = {};arr[2] = 'A';//正確,對字符數組中的元素賦值?arr = {'E','D','F'};//錯誤,對整個數組賦值(可以理解為數組就是一個常量,一旦創建,就無法改變)
-
字符數組名雖然代表地址,但數組名的值不能改變,因為數組名是常量(參照上面案例)
-
對應字符串中的字符的存取,可以用下標法,也可以用指針法。
案例
?#include <stdio.h>?int mian(){//使用兩種方式測試字符串char str1[] = "你好,佩奇!";char *str2 = "你好,喬治!";//賦值測試str1 = "你好啊,佩奇!!";//數組一旦創建就無法改變其值,可以理解為數組名是常量str2 = "你好啊,喬治!!";//打印測試printf("%s,%s\n",str1,str2);/*//以下代碼會報錯//給字符串賦值char *str3 = NULL;//未初始化的指針,指針一定要有指向,需要指向一個具體的內存空間printf("請輸入一個符串:\n");scanf("%s",str3);printf("%s\n ",str3);*/char a[] = "I LOVE YOU";char *b = "I LOVE YOU";//使用下標法和指針法分別訪問字符串printf("%c,%c\n,%c\n",a[2],*(a+2),b[2],*(b+2))return 0;}
字符串作為形式參數
定義
-
實參與形參都可以是字符數組
?void fun(char str[],int len){...}void mian(){char str[] = "hello";fun(str,sizeof(str) / sizeof(str[0]))}
-
實參用字符數組,形參用字符指針
?void fun(char *str,int len){...}void mian(){char *str = "hello";fun(str,sizeof(str) / sizeof(str[0]))}
-
形參和實現都是指針變量(在函數內部中不對字符串中的字符做修改)
?void fun(char *str,int len){//在函數內部中不對字符串中的字符做修改,否則報段錯誤//*(str + 2) = 'A';//str[2] = 'A';printf("%s\n",str);}void mian(){char *str = "hello";fun(str,sizeof(str) / sizeof(str[0]))}
-
實參是指針類型,形參是字符數組(在函數內部中不對字符串中的字符做修改)
?void fun(char str[],int len){//在函數內部中不對字符串中的字符做修改,否則報段錯誤//*(str + 2) = 'A';//str[2] = 'A';printf("%s\n",str);}void mian(){char *str = "hello";fun(str,sizeof(str) / sizeof(str[0]))}
注意
1.字符數組在創建的時候,會在內存中開辟內存空間,內存空間可以存放字符數據;字符指針在創建的時 候,需要依賴于字符數組,字符指針在內存開辟的內存空間中,存放的是數組元素的地址。字符指針的 創建依賴于字符數組,字符數組可以獨立存在,而字符指針不能獨立存在。 2.字符數組可以初始化,但是不能賦值;字符指針可以初始化,也可以賦值。
案例
案例1
-
需求:字符指針作為函數參考:用函數調用實現字符串的復制及長度計算
-
代碼:
?/*************************************************************************> File Name: ? demo04.c> Author: ? ? ? 趙生鑫> Description: ?> Created Time: 2025年03月20日 星期四 16時55分04秒************************************************************************/?#include <stdio.h>?/***定義一個函數,實現字符串的拷貝,返回字符串的長度*@param source拷貝的源字符串*@param target需要拷貝保存字符串的目標字符串*@return 字符串長度** */int str_copy(const char *source,char *target){//定義一個循環變量register int i = 0;?//循環的遍歷while(source[i] != '\0'){//實現拷貝*(target + i) = *(source + i);//指針法?//下標法 target[i] = source[i];?i++;}//拷貝結束后,一定給target加上\0*(target + i) = '\0';??return i;}??int main(int argc,char *argv[]){//定義兩個數組,從鍵盤錄入字符串char source[20],target[20];?printf("請輸入一個字符串:\n");?scanf("%s",source);?//拷貝并復制長度int len = str_copy(source,target);?printf("字符串:%s的長度是%d\n",target,len);?return 0;}?
案例2
-
需求:字符指針作為函數的參數-給定一個字符串,截取start到end之間的字符串,含頭不含尾
-
代碼:
?/*************************************************************************> File Name: ? demo05.c> Author: ? ? ? 趙生鑫> Description: ?> Created Time: 2025年03月20日 星期四 17時08分51秒************************************************************************/?#include <stdio.h>?/**定義一個函數,實現字符串的截取(含頭不含尾)*@param source源字符串*@param start開始截取的位置(下標)*@param end結束截取的位置(下標)*@param target截取出來的字符串*@return target的串長** */int str_substr(const char *source,int start,int end,char *target){//定義循環變量(i時source取的下標,k時target存的下標)register int i = 0,k = 0;?//遍歷源字符串while(source[i] != '\0'){//根據start和end截取if(i >= start && i < end){//下標法target[k] = source[i];*(target + k) = *(source + i);k++;}i++;}//target截取結束,需要添加\0*(target + k) = '\0';return k;}??int main(int argc,char *argv[]){char *str = "abcdefg";char target[26];int len = str_substr(str,2,5,target);printf("%s,%s,%d\n",str,target,len);return 0;}
##