一、前言🎉
閱讀這篇文章你可以學到什么:
- “ ”如何創建一個字串
- “abc”什么時候是常量,什么時候不是常量
- 常見錯誤:修改陣列名
- 常見錯誤:strcpy越界訪問
- 易混點:strcpy與strcmp函式的異同
二、正文現在開始?
- 問題①:將字串賦值給字符指標變數
int main()
{
char*p = "I Love study";
return 0;
}
先來分析一下" "都做了哪三件事:
- 在
只讀區申請中為字串申請了記憶體,用于存放了字串 - 在字串尾部加上‘\0’
- 回傳字串首元素的地址
【總結】我們使用字串的時候,實際使用的是字串的首元素地址而不是字串本身,因此也就不難理解將字串賦值給指標變數的操作了,
- 問題②:用字串初始陣列
int main()
{
char str[] = "abc";
return 0;
}
在這里并不是將該字串的地址賦值給陣列,而是用字串中的各個元素為陣列賦值,怎么理解這個問題呢?我們接下來來討論一下什么時候“abc”什么時候是常量,什么時候不是:
- 不是常量的情況
int main()
{
char str[] = "abc";
return 0;
}
[分析]:
- 首先,我們定義的是一個字符陣列,默認陣列是開辟在
堆疊區上的,堆疊區上的資料是可以被修改的 - 其次,我們定義了一塊空間存盤"abc",這塊空間也就是上面提到的
堆疊區,因此此時的“abc”并不是開辟在只讀區上,也說明了它并不是常量 - 是常量的情況
int main()
{
char* p = "abc";
return 0;
}
[分析]
- 正如我們提到的第一個案例,因為我們并沒有為"abc"申請一塊空間,所以說“ ”為abc在
只讀區上開辟了一塊空間

- 我們可以看到,雖然執行時并沒有報錯,但是除錯時就產生了訪問沖突的的
執行例外,因為我們試圖修改只讀區上的內容,這顯然是不允許的,從中也說明了此時“abc”是一個常量 - 回到剛才的問題
int main()
{
char str[] = "abc";
return 0;
}
- 此時"abc"并不是常量,我們實際是用字串的各個元素對陣列進行的賦值操作
- 因為有了雙引號定界符,所以我們不需要額外的花括號
- 問題③ 為陣列名賦值
int main()
{
char s[10];
s = "abcd";
printf("%s\n", s);
return 0;
}
[分析]
- s是代表字串首元素地址,“abcd”表示該字串首元素地址
- 試想如果賦值成功了,那么s的地址將發生改變,也就意味著我們無法找到之前開辟的陣列空間,那我們之前所開辟的空間不就石沉大海了嗎
- 不只是字符陣列,任何型別的陣列,陣列名的地址值都不能發生改變
int main()
{
int arr[10];
int* p = NULL;
arr++;//錯誤
arr--;//錯誤
arr = p;//錯誤
arr += 10;//錯誤
}
【結論】陣列名是一個指標常量,不可以被修改,通常都是用 int *p = arr[0] 然后通過p的偏移來訪問不同的空間元素,而不會使用arr或者arr[0]來進行操作,案例如下:
int main()
{
char a[10];
char* p = a;
p = "Visual C";//正確
a = "Visual C";//錯誤
return 0;
}
[分析] p是一個指標變數,只不過初始值和a的指向的空間地址相同罷了,
- 問題④:為二維陣列賦值
int main()
{
char str[3][10];
str[1] = "abcd";
}
[分析]
- str[1]是二維陣列str第一行一維陣列的陣列名
- 上文提到,陣列名是指標常量,是不可以被賦值修改的,所以上面是一個錯誤案例
- 問題⑤: strcpy函式實作賦值
//兩陣列內容交換
#include<string.h>
int main()
{
char p[] = "Taylor·Swift";
char q[] = "gorgeous";
char t[13];
strcpy(t,p);
strcpy(p,q);
strcpy(q,t);
return 0;
}
[分析]
- strcpy是一個不安全的函式,為什么這么說呢?不管目標空間是否充足,strcpy都會把source的內容拷貝到destination中去
- 因此如果destination空間不足,就好造成非法訪問記憶體的錯誤,上面的代碼正是犯了這個錯誤
- 易混點①:strcpy函式和strcat函式的異同
(1)strcpy函式
- 引數: char *strcpy( char *strDestination, const char *strSource );
- 功能:strcpy函式將strSource(
包括終止null字符)復制到strDestination指定的位置,復制字串時不執行溢位檢查 - 回傳值:回傳destination的地址
(2)strcat函式
- 引數: char *strcat( char *strDestination, const char *strSource );
- 功能: strcat函式將strSource追加到strDestination,并以一個空字符結束結果字串,strSource的初始字符
覆寫strDestination的終止null字符,復制或附加字串時不執行溢位檢查 - 回傳值:回傳destination的地址
【同】
- 回傳值相同
- 都可以起到復制的作用
- 都不進行溢位檢查(不安全,有越界風險)
【異】
- strcpy從 destination 中第一個元素開始拷貝,直到拷貝到source的NULL為止; strcat 一直找到destination的NULL后才開始追加
strcpy和strcat的自定義實作
#include<string.h>
#include<assert.h>
char* my_strcpy(char* des, const char* src)
{
assert(des && src);//斷言防止des或者src為空指標
char* start = des;
while (*des++ = src++);//巧妙使用 = ,而不是 ==
return start;
}
char* my_strcat(char* des, const char* src)
{
assert(des && src);
char* start = des;
while (*++des);//直到*des為NULL為止
while (*des++ = *src++);
return start;
}
- 課后練習題
練習題①:
int main()
{
char str[50] = "xyz", p1[20] = "abcd", * p2;
p2 = "ABCD";
strcpy(str+2, strcat(p1+1,p2+1));
printf("%s\n", str);
return 0;
}
[分析]
- 首先注意, strcat 一定是找到des的
NULL才開始追加 - 其次,注意 strcat 的回傳值是des的地址,也就是p1+1
- 因此strcat(p1+1, p2+1)的結果就是 "bcdBCD "
- strcpy 則是從傳入位置開始拷貝,所以最終結果就是 xybcdBCD
練習題②:
int main()
{
char Arr1[80] = "AB", Arr2[80] = "LMNP";
int i = 0;
strcat(Arr1, Arr2);
while (Arr1[i++] != '\0')
Arr2[i] = Arr1[i];
printf("%s", Arr2);
}
[分析]
- 注意這里的i++就好,答案是LBLMNPP
練習題③:當輸入串: love Taylor!時,程式的輸出結果
int main()
{
while (putchar(getchar()) != '!');
return 0;
}
[分析]
- 答案為love Taylor!看到答案就明白了吧
練習題④
int main()
{
char a[10] = "1,2,3,4,5";
printf("%d, %d", sizeof(a), strlen(a));
return 0;
}
[分析]
- 逗號有坑到你嗎?反正我是被坑到了
練習題⑤
int main()
{
int i = 0;
char* s = "a\\04\b\\b\xab\06";
while (*s++ && ++i);
printf("%d", i);
return 0;
}
[分析]
- 注意這里的轉義字符: ‘\’ ‘\b’ ‘\xab’ ‘\06’
練習題⑥
int main()
{
char s1[] = "Basic";
char s2[] = "Base";
strcpy(s1,s2);
printf("%s",s1);
return 0;
}
[分析]
- strcpy拷貝的時候別忽略了’\0’也被拷貝過來,所以c其實被‘\0’覆寫
- 因此答案為Base

三、后記
本文部分內容整理自網路,難免片面武斷,讀者如果發現錯誤,還請不吝賜教,今天考完了英語四級,聽力聽的我身心俱疲,讀者老爺們不點個贊再走🤣
轉載請註明出處,本文鏈接:https://www.uj5u.com/ruanti/385668.html
標籤:其他
上一篇:華為網路配置(IPSec)
