1. 基本概念對(duì)比
| 特性 | sizeof | strlen |
|---|---|---|
| 本質(zhì) | 操作符(operator) | 庫函數(shù)(library function) |
| 頭文件 | 不需要 | #include <string.h> |
| 參數(shù) | 數(shù)據(jù)類型或變量 | 只能是以\0結(jié)尾的字符串 |
| 計(jì)算時(shí)機(jī) | 編譯時(shí) | 運(yùn)行時(shí) |
| 返回值含義 | 數(shù)據(jù)類型占內(nèi)存的大小(字節(jié)) | 字符串的實(shí)際長度(不含\0) |
2. 基礎(chǔ)用法示例
#include <stdio.h>
#include <string.h>
int main() {
// ========== sizeof 示例 ==========
printf("=== sizeof 操作符示例 ===\n");
// 對(duì)數(shù)據(jù)類型使用sizeof
printf("sizeof(int) = %zu\n", sizeof(int));
printf("sizeof(double) = %zu\n", sizeof(double));
printf("sizeof(char) = %zu\n", sizeof(char));
// 對(duì)變量使用sizeof
int num = 100;
char ch = 'A';
double d = 3.14;
printf("sizeof(num) = %zu\n", sizeof(num));
printf("sizeof(ch) = %zu\n", sizeof(ch));
printf("sizeof(d) = %zu\n", sizeof(d));
// ========== strlen 示例 ==========
printf("\n=== strlen 函數(shù)示例 ===\n");
char str1[] = "Hello";
char str2[] = "World!";
char *str3 = "C Programming";
printf("strlen(\"Hello\") = %zu\n", strlen("Hello"));
printf("strlen(str1) = %zu\n", strlen(str1));
printf("strlen(str2) = %zu\n", strlen(str2));
printf("strlen(str3) = %zu\n", strlen(str3));
return 0;
}
運(yùn)行結(jié)果:
=== sizeof 操作符示例 ===
sizeof(int) = 4
sizeof(double) = 8
sizeof(char) = 1
sizeof(num) = 4
sizeof(ch) = 1
sizeof(d) = 8
=== strlen 函數(shù)示例 ===
strlen("Hello") = 5
strlen(str1) = 5
strlen(str2) = 6
strlen(str3) = 13
3. 數(shù)組處理的重要區(qū)別
數(shù)組作為參數(shù)時(shí)的行為差異
#include <stdio.h>
#include <string.h>
void test_array(char arr[]) {
printf("在函數(shù)內(nèi)部:\n");
printf("sizeof(arr) = %zu (退化為指針大小)\n", sizeof(arr));
printf("strlen(arr) = %zu\n", strlen(arr));
}
int main() {
char str[] = "Hello World";
printf("在main函數(shù)中:\n");
printf("sizeof(str) = %zu (整個(gè)數(shù)組大小)\n", sizeof(str));
printf("strlen(str) = %zu\n", strlen(str));
printf("\n字符串內(nèi)容:%s\n", str);
printf("數(shù)組長度:%zu\n", sizeof(str)); // 包含\0
printf("字符串長度:%zu\n", strlen(str)); // 不包含\0
// 傳遞給函數(shù)
test_array(str);
return 0;
}
運(yùn)行結(jié)果:
在main函數(shù)中:
sizeof(str) = 12 (整個(gè)數(shù)組大小)
strlen(str) = 11
字符串內(nèi)容:Hello World
數(shù)組長度:12
字符串長度:11
在函數(shù)內(nèi)部:
sizeof(arr) = 8 (退化為指針大小)
strlen(arr) = 11
4. 字符串處理的關(guān)鍵差異
包含\0的字符串處理
#include <stdio.h>
#include <string.h>
int main() {
// 情況1:正常字符串
char normal_str[] = "Hello";
printf("正常字符串: \"%s\"\n", normal_str);
printf("sizeof = %zu, strlen = %zu\n\n", sizeof(normal_str), strlen(normal_str));
// 情況2:包含空字符的字符串
char with_null[] = "Hello\0World";
printf("包含空字符的字符串\n");
printf("字符串內(nèi)容: ");
for(int i = 0; i < sizeof(with_null); i++) {
if(with_null[i] == '\0')
printf("\\0");
else
printf("%c", with_null[i]);
}
printf("\n");
printf("sizeof = %zu (包含所有字符和\\0)\n", sizeof(with_null));
printf("strlen = %zu (遇到第一個(gè)\\0停止)\n\n", strlen(with_null));
// 情況3:字符數(shù)組
char char_array[] = {'H', 'e', 'l', 'l', 'o'}; // 沒有\(zhòng)0結(jié)尾
printf("字符數(shù)組(沒有\(zhòng)\0結(jié)尾):\n");
printf("sizeof = %zu\n", sizeof(char_array));
printf("strlen = %zu (未定義行為,可能繼續(xù)讀取直到遇到\\0)\n", strlen(char_array));
return 0;
}
運(yùn)行結(jié)果:
正常字符串: "Hello"
sizeof = 6, strlen = 5
包含空字符的字符串
字符串內(nèi)容: Hello\0World
sizeof = 12 (包含所有字符和\0)
strlen = 5 (遇到第一個(gè)\0停止)
字符數(shù)組(沒有\(zhòng)0結(jié)尾):
sizeof = 5
strlen = 5 (未定義行為,可能繼續(xù)讀取直到遇到\0)
5. 編譯時(shí)vs運(yùn)行時(shí)計(jì)算
驗(yàn)證計(jì)算時(shí)機(jī)差異
#include <stdio.h>
#include <string.h>
#include <time.h>
// 動(dòng)態(tài)生成字符串的函數(shù)
char* generate_string() {
static char buffer[100];
printf("生成字符串中...\n");
strcpy(buffer, "Dynamic String");
return buffer;
}
int main() {
printf("=== 計(jì)算時(shí)機(jī)驗(yàn)證 ===\n");
// sizeof在編譯時(shí)計(jì)算
printf("1. sizeof在編譯時(shí)確定:\n");
printf(" sizeof(int[100]) = %zu\n", sizeof(int[100]));
printf(" sizeof(\"Hello\") = %zu\n\n", sizeof("Hello"));
// strlen在運(yùn)行時(shí)計(jì)算
printf("2. strlen在運(yùn)行時(shí)計(jì)算:\n");
clock_t start, end;
start = clock();
size_t len = strlen(generate_string());
end = clock();
printf(" 字符串長度: %zu\n", len);
printf(" 計(jì)算耗時(shí): %f秒\n", (double)(end - start) / CLOCKS_PER_SEC);
return 0;
}
運(yùn)行結(jié)果:
=== 計(jì)算時(shí)機(jī)驗(yàn)證 ===
1. sizeof在編譯時(shí)確定:
sizeof(int[100]) = 400
sizeof("Hello") = 6
2. strlen在運(yùn)行時(shí)計(jì)算:
生成字符串中...
字符串長度: 14
計(jì)算耗時(shí): 0.000012秒
6. 實(shí)際應(yīng)用場景對(duì)比
內(nèi)存分配和字符串操作
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
int main() {
printf("=== 實(shí)際應(yīng)用場景 ===\n");
// 場景1:內(nèi)存分配
char source[] = "This is a test string";
// 錯(cuò)誤的做法:使用strlen分配內(nèi)存(會(huì)少1個(gè)字節(jié)給\0)
// char *dest1 = (char*)malloc(strlen(source)); // 錯(cuò)誤!
// 正確的做法:使用sizeof或strlen+1
char *dest2 = (char*)malloc(sizeof(source)); // 方法1:使用sizeof
char *dest3 = (char*)malloc(strlen(source) + 1); // 方法2:使用strlen+1
strcpy(dest2, source);
strcpy(dest3, source);
printf("源字符串: %s\n", source);
printf("使用sizeof分配: %s (大小: %zu)\n", dest2, sizeof(source));
printf("使用strlen+1分配: %s (長度: %zu)\n", dest3, strlen(source));
free(dest2);
free(dest3);
// 場景2:數(shù)組遍歷
printf("\n=== 數(shù)組遍歷示例 ===\n");
int numbers[] = {1, 2, 3, 4, 5};
int count = sizeof(numbers) / sizeof(numbers[0]); // 計(jì)算元素個(gè)數(shù)
printf("數(shù)組元素個(gè)數(shù): %d\n", count);
printf("遍歷數(shù)組: ");
for(int i = 0; i < count; i++) {
printf("%d ", numbers[i]);
}
printf("\n");
return 0;
}
運(yùn)行結(jié)果:
=== 實(shí)際應(yīng)用場景 ===
源字符串: This is a test string
使用sizeof分配: This is a test string (大小: 22)
使用strlen+1分配: This is a test string (長度: 21)
=== 數(shù)組遍歷示例 ===
數(shù)組元素個(gè)數(shù): 5
遍歷數(shù)組: 1 2 3 4 5
7. 常見錯(cuò)誤和陷阱
容易混淆的情況
#include <stdio.h>
#include <string.h>
int main() {
printf("=== 常見陷阱示例 ===\n");
// 陷阱1:指針vs數(shù)組
char str_array[] = "Hello";
char *str_pointer = "Hello";
printf("char str_array[] = \"Hello\";\n");
printf("char *str_pointer = \"Hello\";\n\n");
printf("sizeof(str_array) = %zu (數(shù)組大小)\n", sizeof(str_array));
printf("sizeof(str_pointer) = %zu (指針大小)\n", sizeof(str_pointer));
printf("strlen(str_array) = %zu\n", strlen(str_array));
printf("strlen(str_pointer) = %zu\n\n", strlen(str_pointer));
// 陷阱2:字符串字面量
printf("字符串字面量:\n");
printf("sizeof(\"Hello\") = %zu (包含\\0)\n", sizeof("Hello"));
printf("strlen(\"Hello\") = %zu (不包含\\0)\n\n", strlen("Hello"));
// 陷阱3:結(jié)構(gòu)體中的差異
struct Test {
char name[20];
char *title;
};
printf("結(jié)構(gòu)體大小分析:\n");
printf("sizeof(struct Test) = %zu\n", sizeof(struct Test));
printf("其中name數(shù)組占20字節(jié),指針占%zu字節(jié)\n", sizeof(char*));
return 0;
}
運(yùn)行結(jié)果:
=== 常見陷阱示例 ===
char str_array[] = "Hello";
char *str_pointer = "Hello";
sizeof(str_array) = 6 (數(shù)組大小)
sizeof(str_pointer) = 8 (指針大小)
strlen(str_array) = 5
strlen(str_pointer) = 5
字符串字面量:
sizeof("Hello") = 6 (包含\0)
strlen("Hello") = 5 (不包含\0)
結(jié)構(gòu)體大小分析:
sizeof(struct Test) = 28
其中name數(shù)組占20字節(jié),指針占8字節(jié)
8. 總結(jié)記憶技巧
核心區(qū)別口訣:
- sizeof:看類型,算大小,編譯時(shí)期就確定
-
strlen:找
\0,數(shù)長度,運(yùn)行時(shí)候才計(jì)算
使用建議:
- 內(nèi)存操作用sizeof
- 字符串處理用strlen
- 數(shù)組傳參要注意sizeof退化
-
內(nèi)存分配記得給
\0留空間