1. 程式人生 > 實用技巧 >計算機程式設計實訓記錄(5)

計算機程式設計實訓記錄(5)

前面關於排序演算法的任務沒有完成,我...我實在不知道怎麼辦了QAQ
不管了,跳過這個寫後面的吧。


C-字串處理

字串處理簡介

字串是程式設計中常用的一種資料。然而 C 語言中的字串(常稱為 C-字串)的概念、操作卻涉
及到陣列、指標、函式等概念。也正是這個原因,使得有關 C-字串的練習成為理解和掌握陣列、指標、
函式操作的極佳素材。
C-字串按字元陣列的形式存放在計算記憶體中,並且以特殊字元'\0'作為串結束標誌。其中的字元數
組被稱為字串的 容器,一般陣列、動態陣列(即堆陣列)或常量陣列都可能成為 C-字串的容器。C-字
符串的容器常常需要程式設計師花額外的精力進行管理,特別是需要保證有“足夠大”的容量。
由於 C-字串在記憶體中連續存放,又有串結束標誌字元,並且認為其容器已經設定妥當且容量“足夠
大”,在這樣的前提下,在 C 語言程式中,常將 char或 const char

型別理解為 C-字串(變數)及
C-字串常量。


字串處理反例

反例一

#include <stdio.h>
 void GETS(char *p)
 {
     printf("\nInput a string: ");
     scanf("%s", p);
 }
 int main()
 {
     char *p1, *p2="Hello world!";
     GETS(p1);
     printf("%s\n", p1);
     GETS(p2);
     printf("%s\n", p2);
     return 0;
 }

這個程式是可以編譯通過的,但是我們不難發現,p1指向不明,而p2指向不可寫的常量區,當我們執行的時候就會無法輸入。
那該怎麼修改呢?

char p1[80], p2[80];

或者

char *p1, p2[80];
p1 = (char*)malloc(80);
// ……
free(p1);

反例二

#include <stdio.h>
int main()
{
  unsigned long x=1234567890;
  char p[5];
  unsigned long y=4210356789;
  gets(p);
		// 輸入字串,可能破壞x
  x = 1234567890;
		//修改x的值可能影響超長的字串
  return 0;
}

這個程式同樣沒有錯誤,但是可靠性不高。

串長<5時,無事發生。

串長<28時,同樣無事發生。

串長=28時,不可思議的事情發生了,在修改了x的值後字串變化了。

串長>28時,不可思議的事情發生了,x和字串都遭到過破壞。
不過,我們同樣可以發現,無論x和str怎麼變化,y都不受影響。
我們可以用一張圖來解釋這一切:

可以看到,y作為後宣告的變數佔據了最外層的記憶體空間,str的大小和x的再賦值都影響不到y。


C-字串處理常見錯誤

  1. 關於容器:
    • 沒有設定容器
    • 容器位於常量區
    • 容器的容量太小
  2. 關於串結束標誌:
    • 沒有在適當的位置設定串結束標誌
    • 串結束標誌被破壞
  3. 直接使用賦值運算子、關係運算符等
    • 字串拷貝 (應該使用strcpy函式)
    • 字串拼接 (應該使用strcat函式)
    • 字串比較 (應該使用strcmp函式)

課程任務

自定義函式實現C-字串基本操作

C 語言中,對 C-字串的操作體現在若干標準函式,如 strlen、strcpy、strncpy、strcat、strcmp、
atoi、atof、gets、puts、sprintf, sscanf 等。
本部分練習要求實現如下 5 個函式,函式原型已經給定:

unsigned int StrLen(const char *str); // 計算字串的長度
char *StrCpy(char *dest, const char *source); // 字串複製(拷貝)
char *StrCat(char *dest, const char *source); // 字串拼接
int StrCmp(const char *str1, const char *str2); // 字串比較(按 ASCII 序)
int AtoI(const char *str); // 將字串轉換成整數

StrLen

遍歷一遍即可

unsigned int StrLen(const char *str)// 計算字串的長度
{
    unsigned int i;
    for(i=0;str[i];i++);
    return i;
}

StrCpy

同樣遍歷一遍

char *StrCpy(char *dest, const char *source) // 字串複製(拷貝)
{
    int i;
    for(i=0;source[i];i++)
    {
        dest[i]=source[i];
    }
    dest[i+1]='\0';
    return dest;
}

StrCat

這裡可以用到前面的StrLen

char *StrCat(char *dest, const char *source) // 字串拼接
{
    int i;
    unsigned int n;
    n=StrLen(dest);
    for(i=0;source[i];i++)
    {
        dest[n+i]=source[i];
    }
    return dest;
}

不過奇怪的是,我一開始使用dest[StrLen(dest)+i]=source[i];卻無法實現,可能是型別轉換的問題?

StrCmp

首先我們要知道作為原型的strcmp()是怎麼一回事。