網站首頁 編程語言 正文
字符串的本質就是字符數組,將字符串作為字符數組來處理。字符數組和字符串都可以作為存放字符的數組,所以可以通過數組的下標訪問每一個字符。字符串比較正如在C++中可以用3種方法(字符數組、字符串(類)、字符指針)訪問一個字符串,比較字符串(內容)自然也有這三種基本形式。
字符串是一種重要的數據類型,但是c語言并沒有顯示的字符串數據類型,因為字符串以字符串常量的形式出現或者存儲于字符數組中。在C++標準模板庫(STL)中提供了string類,實現了對字符串的封裝。但是其實現原理還是居于字符和指針,要了解這個原理,我們先看一下有關字符數組、字符和字符串之間的一些關聯。
區別:字符數組的長度就是字符的總長度,而字符串會+1,是因為包含了最后的“\0”結束符。
一、字符指針、字符數組
字符指針
字符串指針變量本身是一個變量,用于存放字符串的首地址。而字符串本身是存放在以該首地址為首的一塊連續的內存空間中并以 \0 作為串的結束。
char *ps="C Language";
順序是:1.分配內存給字符指針;2.分配內存給字符串;3.將字符串首地址賦值給字符指針;
char *ps; // ps 字符串指針,是指針,是一個變量
ps="C Language"; // ps 為字符串的首地址,利用 ps++ 可遍歷字符串,字符串存儲在以 ps 為開始地址的地段連續的內存空間中,并以 \0 作為字符串的結束。
這里有兩點需要考慮清楚的地方:
1、*a 只是指向一個字符。
舉例如下:
#include <stdio.h>
#include <stdlib.h>
int main(void){
char *a= "bcd" ;
printf("輸出字符:%c \n", *a); /*輸出字符,使用"%c"*/
printf("輸出字符:%c \n", *(a+1) ); /*輸出字符,使用"%c"*/
printf("輸出字符串:%s \n", a); /*輸出字符串,使用"%s";而且a之前不能有星號"*" */
system("pause"); /*為了能看到輸出結果*/
}
運行結果如下:
輸出字符:b
輸出字符:c
輸出字符串:bcd
2、若字符串常量出現在在表達式中,代表的值為該字符串常量的第一個字符的地址。所以 hello 僅僅代表的是其地址。原聲明方式相當于以下聲明方式:
char *a;
a="hello"; /*這里字符串"hello"僅僅代表其第一個字符的地址*/
字符數組
字符數組是由于若干個數組元素組成的,它可用來存放整個字符串。(即用字符數組來存放字符串)。
在 C 語言中,將字符串作為字符數組來處理。(C++中不是)
字符數組初始化的方法:
1). 可以用字符串常量來初始化字符數組:
char str[]={"Iamhappy"};
可以省略花括號
char str[]="Iamhappy"; # 系統自動加入 \0
注意:上述這種字符數組的整體賦值只能在字符數組初始化時使用,不能用于字符數組的賦值,字符數組的賦值只能對其元素一一賦值。
下面的賦值方法是錯誤的:
char str[20];
str="Iamhappy";
對字符數組的各元素逐個賦值。
char str[10]={'I','','a','m','','h','a','p','p','y'};
在 C 語言中,可以用兩種方法表示和存放字符串:
(1)用字符數組存放一個字符串
char str[]="IloveChina";
(2)用字符指針指向一個字符串
char *str="IloveChina";
兩種表示方式的字符串輸出都用:printf("%s\n", str);
%s 表示輸出一個字符串,給出字符指針變量名 str(對于第一種表示方法,字符數組名即是字符數組的首地址,與第二種中的指針意義是一致的),則系統先輸出它所指向的一個字符數據,然后自動使 str 自動加 1,使之指向下一個字符...,如此,直到遇到字符串結束標識符 \0 。
二、字符串指針
string* str 可以賦值:
string* str = {"hello", "world"};
// 對比與 char *name = "wang" = {'w','a','n','g'}
// *(str) = "hello", *(str+1) = "world"
// *(*(str)+1) = 'e'
也就是說每個元素都是 string 類型的,跟 char* 是不一樣的,不過 string* 可以用 char** 來代替:
string = char*, string* = char**
三、(字符串)指針數組
實例
#include <stdio.h>
void main()
{
char *str[] = {"Hello", "C++", "World"}; //char (*str)[] = ...
int i;
for(i=0; i<3; i++)
printf("%s\n", str[i]);
}
// str[0]字符串"hello"的首地址,str[0]+1:字符串"hello"第二個字符'e'的地址,str[2]=str+2:第三個字符串"world"的首地址
// str[1]字符串"C++"的首地址
// str[2]字符串"world"的首地址
或
實例
#include <stdio.h>
#include <string.h>
int main()
{
char *str[] = {"Hello", "C++", "World"};
char **p;
for(p=str; p<str+3; p++)
puts(*p); #*p為字符串首地址,*p[0]為字符串的第一個字符地址
}
或
實例
#include<stdio.h>
#include<stdlib.h>
int main()
{
char *str[3]={"Hello","C++","World"};
printf("%s,%s,%c",str[0],str[0]+1,*(*(str+2)+1));
system("pause");
}
結果為:
Hello,ello,o
格式:char* na[N] = {"li", "zh", "li", "zh", "li"};
char *a[]:表示a是數組,數組中的元素是指針,指向char類型,(數組里面所有的元素是連續的內存存放的) 數組名是數組第一個字節的內存地址,并且數組名a也表示指針。所以a 并不表示a地址存儲的內容, 而是a地址本身。
a+1:表示 a 的第二個元素的內存地址, 所以是加 8 字節。( 因為a的元素是char 指針, 所需要的空間為8字節(64位內存地址)。 )
*(a+1):則表示a這個數組的第二個元素的內容 (是個char 類型的指針,本例表示為world字符串的地址)。
*(*(a+1)):則表示a這個數組的第二個元素的內容(char指針)所指向的內容(w字符).
char * a[10]:表示限定這個數組最多可存放10個元素(char指針), 也就是說這個數組占用10*8 = 80字節。
#w: a+1 => *(a+1) => *(a+1)[0]
指針(地址) 指針內容(字符串) 字符
四、總結
char *argv:理解為字符串
char **argv:理解為字符串指針
char *argv[]:字符串指針數組
int main(int argc, char*argv[]) 這是一個典型的數組名(或者說是指針數組)做函數參數的例子,而且還是沒有指定大小的形參數組。
有時為了再被調用函數中處理數組元素的需要,可以另設一個形參,傳遞需要處理的數組元素的個數。而且用數組名做函數實參時,不是吧數組元素的值傳遞給形參,而是把實參數組的首元素的地址傳遞給形參數組,這樣兩個數組久共同占有同一內存單元。 和變量作函數參數的作用不一樣。
可以去看看關于數組作為函數參數和指針數組作main函數形參方面的例子。譚浩強的那本書講的很細,對這個有詳細的解釋。
1. 當 char [] 作為函數的參數時, 表示 char *. 當作為函數的參數傳入時, 實際上是拷貝了數組的第一個元素的地址。
所以 void test (char a[]) 等同于 void test ( char * a )
char x[10] ;
然后調用 test(x) 則等同于把 x 的第一個元素的地址賦予給參數 a。
2. char * a 和 char a[]
- 相同點 : a都是指針, 指向char類型。
- 不同點 : char a[] 把內容存在stack。char *a 則把指針存在 stack,把內容存在 constants。
3. char * a[10] 和 char a[10][20]
- 相同點 : a 都是2級指針, *a 表示一級指針, **a 表示內存中存儲的內容。
- 不同點 : char * a[10], 數組由char * 類型的指針組成; char a [10][20] 表示一位放10個元素, 二維放20個元素, 值存放地是一塊連續的內存區域, 沒有指針。
4. 小竅門 : [] 和 * 的數量對應, 如 char a[][] 的指針層數是 2, 相當于 char **a; char *a[] 也是如此, 兩層指針. 迷糊的時候數數到底有幾個 * 幾個 [], 就知道什么情況下存儲的是內容還是地址了 ? 如 char a[][] 的情況里面: &a, a, *a 都是地址, **a 是內容。
相關推薦
- 2022-05-19 Nginx+Windows搭建域名訪問環境的操作方法_nginx
- 2022-05-29 C#使用DirectX.DirectSound播放語音_C#教程
- 2022-06-28 C#基于自定義事件EventArgs實現發布訂閱模式_C#教程
- 2022-03-10 你知道如何自定義sort函數中的比較函數_C 語言
- 2022-11-25 詳解React中Fragment的簡單使用_React
- 2023-05-24 python實現對AES加密的視頻數據流解密的方法_python
- 2022-06-09 Nginx動靜分離配置實現與說明_nginx
- 2022-02-28 npm ERR! code CERT_HAS_EXPIRED npm ERR! errno CERT
- 最近更新
-
- window11 系統安裝 yarn
- 超詳細win安裝深度學習環境2025年最新版(
- Linux 中運行的top命令 怎么退出?
- MySQL 中decimal 的用法? 存儲小
- get 、set 、toString 方法的使
- @Resource和 @Autowired注解
- Java基礎操作-- 運算符,流程控制 Flo
- 1. Int 和Integer 的區別,Jav
- spring @retryable不生效的一種
- Spring Security之認證信息的處理
- Spring Security之認證過濾器
- Spring Security概述快速入門
- Spring Security之配置體系
- 【SpringBoot】SpringCache
- Spring Security之基于方法配置權
- redisson分布式鎖中waittime的設
- maven:解決release錯誤:Artif
- restTemplate使用總結
- Spring Security之安全異常處理
- MybatisPlus優雅實現加密?
- Spring ioc容器與Bean的生命周期。
- 【探索SpringCloud】服務發現-Nac
- Spring Security之基于HttpR
- Redis 底層數據結構-簡單動態字符串(SD
- arthas操作spring被代理目標對象命令
- Spring中的單例模式應用詳解
- 聊聊消息隊列,發送消息的4種方式
- bootspring第三方資源配置管理
- GIT同步修改后的遠程分支