程序是對數據的表示和處理。對于數值型數據,可以直接處理;對于數值型以外的數據,例如文本(字符和字符串),圖形圖像,音頻視頻,還涉及到數據的表示(數據編碼)的問題。
1 C語言對字符和字符常量的約定字符編碼有ASCII、GB2312,Unicode等。處理字符或字符串數據時,其實質是對字符編碼的操作。ASCII編碼使用一個字節的整數來編碼西文字符,而整數在計算機中是區分signed和unsigned的,對于unsigned的,一個字符的表示範圍是0-255(0x00000000-0xFFFFFFFF),對于signed,通常使用補碼來編碼,也就是區分符号,一個字節的值域(表示的整數範圍)是:-128~127,雖然ASCII隻使用了0x00000000~0x0FFFFFFF的區段(0-127),但字符類型為了與數值型整數在處理時達到統一,char類型也可以區分unsigned和signed,char默認是signed的。
ASCII對數字字符進行連續編碼,字符轉數字隻需減去'0'即可:
char ch = '3';
int d = ch-'0'; // 字符轉數字
ASCII對大寫字母和小寫字母也進行了連續編碼,為方便處理(包括大小寫轉換),但其編碼值做了特殊考慮:
Bin |
Oct |
Dec |
Hex |
縮寫/字符 |
解釋 |
(二進制) |
(八進制) |
(十進制) |
(十六進制) | ||
0100 0001 |
101 |
65 |
0x41 |
A |
大寫字母A |
0110 0001 |
141 |
97 |
0x61 |
a |
小寫字母a |
大、小寫字母隻有在第6位(從低位到高位)存在區别,這樣在大小寫轉換時特别方便。
char str[] = "AbCdEf";
char *p = str;
while(*p!='\0')
(*p ) |= 'a'-'A'; // 如果是大寫,改成小寫,将log2('a'-'A')=log2(32),将低位到高位的第6位置1;
printf("%s\n",str); // abcdef
p = str;
while(*p!='\0')
(*p ) &= ~('a'-'A'); // 如果是小寫,改成大寫,将log2('a'-'A')=log2(32),将低位到高位的第6位置0;
printf("%s\n",str); // ABCDEF
轉義字符也可以用ASCII碼來表示字符,但隻能用8進制或16進制,8進制0開頭例如'\023'且最多3位、16進制x開頭例如'\xa'且最多兩位;
printf("%c %c %c\n",'\060',48,'\x30');// 0 0 0,用8進制表示轉義字符時,前導0可以省略
printf("%c %c %c\n",'\101',65,'\x41');// A A A,用8進制表示轉義字符時,如果超過3位,不要用前導0
printf("%c %c %c\n",'\0101',65,'\x41');// 1 A A
// '\0101'在内存中變成了831h,四個位存儲'\010',也就是8h,四個位存儲'1',也就是31h,
// 其整數就是831h,截斷成一個字節後就是31h,也就是字符'1'
在C中,unicode編碼的字符一般以wchar_t類型存儲,固定使用兩個字符的長度。
typedef unsigned short wchar_t;
#include<stdio.h>
#include<stdlib.h>
#include <locale.h>
int main(void)
{
char s[]="中";//漢字在C/C 中是用2個字節表示
printf("%d %d\n",s[0],s[1]);
char m[3];
m[0]=-42;
m[1]=-48;
m[2]=0;
puts(m);//兩個字節連起來湊成一個漢字。
printf("%c%c\n",s[0],s[1]);
printf("%c%c\n",214,208);//d6,d0
//都是字符256模數的關系(補碼 其負數補碼 = 模)
setlocale(LC_ALL, "chs");
wchar_t wc = L'\x4E2D';
wprintf(L"%c\n",wc);
system("pause");
return 0;
}
/*
-42 -48
中
中
中
中
*/
中英文混合的字符統計:
#include <stdio.h>
#include <string.h>
int gbk_strlen(char* str)
{
char* p = str; //p用于後面遍曆
while(*p) //若是結束符0,則結束循環
{
if(*p < 0 && (*(p 1)<0 || *(p 1) < 63)) //中文漢字情況
{
str ; //str移動一位,p移動移動2位,因此長度加1
p = 2;
}
else
p ; //str不動,p移動一位,長度加1
}
return p-str; //返回地址之差
}
int main()
{
char str[] = "abc你好123中國456";
printf("%d\n",strlen(str)-gbk_strlen(str)); // 4
getchar();
}
C語言中,字符串是借助于字符型的一維數組來存放的,并規定以字符'\0'作為字符串結束标志。由前面的知識我們知道,‘\0'是一個轉義字符,稱為“空值”,它的ASCII編碼值為0。‘\0'作為标志占用存儲空間,但不計入串的實際長度。
在字符串輸出或逐個字符處理時,或者需要其長度信息,或者有一個結束标志,如果選擇一個結束标志,在字符串處理時會更加方便。循環時可用字符結束标志作為循環結束标志,在用作函數參數時,不需要額外提供一個長度參數。
例如字符串處理的庫函數都是以'\0'結束标志為循環終止條件的,包括strlen(),如果用strlen()去處理字符數組,除非其有一個顯式'\0'的聲明,否則會出錯。
char str[] = "abc456";// 有一個隐式的'\0'存儲
char chs[] = {'a','b','c','4','5','6'};
printf("%s %s\n",str,chs); // abc456 abc456燙abc456
printf("%d %d %d %d",sizeof(str),sizeof(chs),strlen(str),strlen(chs)); // 7 6 6 14,14是一個随機值;
雖然C語言中沒有字符串數據類型,但卻允許使用“字符串常量”。字符串常量是由雙引号括起來的一串字符,在表示字符串常量時,不需要人為在其末尾加入‘\0’,例如字符串常量”Hello!”不必寫成“Helllo!\0”,C編譯程序将自動完成這一工作,在末尾加上結束标志'\n'。
字符串常量與其它常量不一樣,其存儲在内存的常量區。
4 C語言中字符串常量給出的是地址值。一個字符串常量都分别占用内存中一串連續的存儲空間。這些連續的存儲空間實際上就是字符型的一維數組。這些數組雖然沒有名字,但C編譯系統卻以字符串常量的形式給出存放每一字符串的存儲空間的首地址,不同的字符串具有不同的起始地址。也就是說,在C語言中,字符串常量被隐含的處理成了一個以'\0'結尾的無名字符型一維數組。因此,若有以下定義:
char*sp, s[10];
則以下賦值語句是不合法的。
s = "Hello!";
因為,字符串常量在賦值過程中給出的是這個字符串在内存中所占的一串連續存儲單元的首地址,而s是一個不可重新賦值的數組名,因此,些賦值不合法,而以下賦值是合法的。
sp="Hello!";
此賦值語句并不是把字符串的内容放入sp中,而隻是把字符串在内存中所占的首地址賦予了char類型的指針變量 sp,使指針變量 sp 指向該字符串。
當然,也不能使用sp去修改其指向的常量值,如
sp[2] = 'L'; // 非法操作
如果需要操作字符元素,将其存儲到數組中即可。
5 字符數組與字符串的區别字符數組的每個元素中可存放一個字符,但它并不限定最後一個字符應該是什麼,而在C語言中,因為有關字符串的大量操作都與串結束标志'\0'有關,因此,在字符數組中的有效字符後面加上'\0'這一特定操作後,我們就可以把這種一維字符型數組"看作”字符串變量,但它又不同于一般的變量。要注意的是,僅僅可以在字符數組内存放字符串,不能通過賦值語句将字符串常量或其他字符數組中的字符串直接賦給字符串變量。換句話說,字符串是字符數組的一種具體應用。
看彙編:
5: char arr[] = "Hello";
00401028 mov eax,[string "hellow" (00422f78)]
0040102D mov dword ptr [ebp-8],eax
00401030 mov cx,word ptr [string "hellow" 4 (00422f7c)]
00401037 mov word ptr [ebp-4],cx
6: char *p = "Hello";
0040103B mov dword ptr [ebp-0Ch],offset string "hellow" (00422f78)
字符串常量存儲在常量區,例如上例"Hello"存儲在(00422f78)。
6 字符串與文本文檔小的文本文檔你可以用一個字符串或字符串數組來處理,使用'\n\做換行來分段即可。
大的文本文檔你可以通過鍊表(鍊式存儲)來存儲,鍊表的一個節點可以存儲一個段落。
與文本文檔相關的輸入輸出,使用FILE結構體和相應的一些文件處理函數即可完成。
-End-
,更多精彩资讯请关注tft每日頭條,我们将持续为您更新最新资讯!