簡體   English   中英

關於克尼根和里奇練習2-3的問題

[英]Questions about a Kernighan and Ritchie Excercise 2-3

我正在嘗試用C編寫一個將十六進制數字轉換為整數的程序。 我已經成功編寫了將八進制轉換為整數的程序。 但是,一旦我開始使用字母(af),問題就會開始。 我對該程序的想法是廣告如下:

  1. 參數必須是以0x或0X開頭的字符串。

  2. 參數十六進制數存儲在char字符串s []中。

  3. 整數n初始化為0,然后根據規則進行轉換。

我的代碼如下(我只讀了K&R的p37,所以對指針了解不多):

/*Write a function htoi(s), which converts a string of hexadecimal digits (including an optional 0x or 0X) into its equivalent integer value. The allowable digits are 0 through 9, a through f, and A through F.*/

#include <stdio.h>
#include <string.h>
#include <math.h>
#include <ctype.h>

int htoi(const char s[]) { //why do I need this to be constant??
    int i;
    int n = 0;
    int l = strlen(s);
    while (s[i] != '\0') {
        if ((s[0] == '0' && s[1] == 'X') || (s[0] == '0' && s[1] == 'x')) {
            for (i = 2; i < (l - 1); ++i) {
                if (isdigit(s[i])) {
                    n += (s[i] - '0') * pow(16, l - i - 1);
                } else if ((s[i] == 'a') || (s[i] == 'A')) {
                    n += 10 * pow(16, l - i - 1);
                } else if ((s[i] == 'b') || (s[i] == 'B')) {
                    n += 11 * pow(16, l - i - 1);
                } else if ((s[i] == 'c') || (s[i] == 'C')) {
                    n += 12 * pow(16, l - i - 1);
                } else if ((s[i] == 'd') || (s[i] == 'D')) {
                    n += 13 * pow(16, l - i - 1);
                } else if ((s[i] == 'e') || (s[i] == 'E')) {
                    n += 14 * pow(16, l - i - 1);
                } else if ((s[i] == 'f') || (s[i] == 'F')) {
                    n += 15 * pow(16, l - i - 1);
                } else {
                    ;
                }
            }
        }
    }
    return n;
}


int main(void) {
    int a = htoi("0x66");
    printf("%d\n", a);
    int b = htoi("0x5A55");
    printf("%d\n", b);
    int c = htoi("0x1CA");
    printf("%d\n", c);
    int d = htoi("0x1ca");
    printf("%d\n", d);
} 

我的問題是:

1.如果我在htoi的參數中不使用const,我會從g ++編譯器得到以下警告:

2-3.c:在函數'int main()'中:2-3.c:93:20:警告:不建議從字符串常量轉換為'char *'[-Wwrite-strings] 2-3.c:97 :22:警告:不建議將字符串常量轉換為'char *'[-Wwrite-strings] 2-3.c:101:21:警告:不建議將字符串常量轉換為'char *'[-Wwrite-strings] 2 -3.c:105:21:警告:不建議將字符串常量轉換為'char *'[-Wwrite-strings]

為什么是這樣?

2.為什么我的程序要花這么多時間運行? 我還沒有看到結果。

3.為什么在終端中輸入cc 2-3.c而不是g ++ 2-3.c時出現以下錯誤消息:

“未定義對'pow'的引用”

在我使用冪函數的每一行上?

4.請指出我程序中的其他錯誤/潛在的改進。

  1. const char []表示您不能在函數中更改它。 const為not const會發出警告。 關於const 查看其Wikipedia頁面
  2. -
  3. cc可能沒有鏈接正確的庫。 請嘗試以下構建命令: cc 2-3.c -lm

改進:

  1. 不要使用pow() ,這在處理時間方面非常昂貴。
  2. 對字母使用與對數字相同的技巧以獲取值,而不要使用固定的“魔術”數字。
  3. 您不需要最后的else部分。 只需將其保留為空(或在其中輸入錯誤消息,因為不允許使用這些字符)。

祝好運!

關於我對pow()調用的評論(使用上述hexchar_to_int()函數hexchar_to_int() ,這就是我要實現這一點的方式(不進行錯誤檢查):

  const char *t = "0x12ab";
  int i = 0, n = 0;
  int result = 0;
  for (i = 2; i < strlen(t); i++) {
   n = hexchar_to_int(t[i]);

   result |= n; 
   result <<= 4;
  } 

  /* undo the last shift */
  result >>= 4;

不要使用C ++編譯器來編譯C程序。 那是我對你的第一個建議。

其次const在一個函數參數char *確保程序員不小心修改字符串。

第三,如上所述,您需要在數學庫中包含-lm

如果我在htoi的參數中不使用const,我會從g ++編譯器收到以下警告

const參數應該存在,因為它被認為是永遠不會從指針類型轉換const的良好而正確的編程。 字符串文字“ ...”應視為常量,因此,如果沒有const作為參數,則編譯器會認為您正在拋棄const限定符。

此外,您應將所有您不打算修改const的內容的指針參數聲明為const,即術語const正確性

為什么我的程序需要這么多時間才能運行? 我還沒有看到結果。

我認為主要是因為您進行了初始化。 int i; 我含有垃圾。 然后while (s[rubbish_value] != '\\0') 此功能也可以編寫得更好。 首先檢查字符串開頭的0x,如果不存在,則提示錯誤(返回NULL?),否則丟棄它們。 然后再開始一個單循環,則不需要2個循環。

請注意,pow()函數處理浮點數,這會使您的程序變慢一點。 您可以考慮使用僅整數版本。 不幸的是,標准C中沒有這樣的功能,因此您將不得不在其他地方找到它。

還要考慮函數isxdigit(),它是ctype.h中的標准函數,它檢查數字0-9以及十六進制字母AF或af。 但是,這可能對性能沒有幫助,因為您將需要對數字和字母執行不同的計算。

值得一提的是,以下代碼片段顯示了如何將單個char轉換為十六進制int。 它不是最優化的版本,但是它利用了可用的標准功能,以提高可讀性和可移植性:

#include <ctype.h>

uint8_t hexchar_to_int (char ch)
{
  uint8_t result;

  if(isdigit(ch))
  {
    result = ch - '0';
  }
  else if (isxdigit(ch))
  {
    result = toupper(ch) - 'A' + 0xA;
  }
  else
  {
    // error
  }

  return result;
}

我只是自己完成了此練習,我認為主要思想之一是利用可以將char作為整數進行比較的知識(他們在第二章中對此進行了討論)。

這是我的功能供參考。 認為這可能是有用的,因為這本書不包含練習的答案。

int htoi(char s[]) {
    int i = 0;
    if(s[i] == '0') {
        ++i;
        if(s[i] == 'x' || s[i] == 'X') {
          ++i;
        }
    }

    int val = 0;

    while (s[i] != '\0') {
        val = 16 * val;
        if (s[i] >= '0' && s[i] <= '9')
            val += (s[i] - '0');
        else if (s[i] >= 'A' && s[i] <= 'F') 
            val += (s[i] - 'A') + 10;
        else if (s[i] >= 'a' && s[i] <= 'f')
            val += (s[i] - 'a') + 10;
        else {
            printf("Error: number supplied not valid hexadecimal.\n");
            return -1;
        }           
        ++i;
    }

    return val;
}

始終將變量int i=0初始化為int i=0 ,否則i將包含一個垃圾值,可以是任意數字,而不是您期望的0。 您正在無限循環中運行while語句,這就是為什么要花很多時間才能得到結果,打印i來了解原因。 另外,如果字符串不是以0x開頭,請添加一個中斷,這樣可以避免在用戶使用隨機字符串時出現相同的循環問題。 正如其他人提到的那樣,您需要導入包含pow函數的庫,並使用const聲明字符串以擺脫警告。

這是我針對上述問題的程序版本。 它將十六進制字符串轉換為十進制數字,而與可選前綴(0x或0X)無關。 使用的4個重要庫函數是strlen,isdigit(c),isupper(c),isxdigit(c),pow(m,n)

歡迎提出改進代碼的建議:)

/*Program  - 5d Function that converts hex(s)into dec -*/
#include<stdio.h>
#include<stdlib.h>
#include<math.h>                //Declares mathematical functions and macros
#include<string.h>              //Refer appendix in Page 249 (very useful)
#define HEX_LIMIT 10

int hex_to_dec(char hex[])      //Function created by me :)
{
   int dec = 0;                //Initialization of decimal value
   int size = strlen(hex);     //To find the size of hex array
   int temp = size-1 ;         //Pointer pointing the right element in array
   int loop_limit = 0;         //To exclude '0x' or 'OX' prefix in input

   if(hex[0]=='0' && ((hex[1]=='x')  || (hex[1]=='X')))
   loop_limit = 2;

   while(temp>=loop_limit)
   {
     int hex_value = 0;        //Temporary value to hold the equivalent hex digit in decimal

     if(isdigit(hex[temp]))
       hex_value = (hex[(temp)]-'0') ;
     else if(isxdigit(hex[temp]))
        hex_value =  (toupper(hex[temp])-'A' + 10);
     else{
        printf("Error: No supplied is not a valid hex\n\n");
        return -1;
      }

    dec += hex_value * pow(16,(size-temp-1));        //Computes equivalent dec from hex
    temp--;                    //Moves the pointer to the left of the array
   }
   return dec;
}

int main()
{
char hex[HEX_LIMIT];
printf("Enter the hex no you want to convert: ");
scanf("%s",hex);
printf("Converted no in decimal: %d\n", hex_to_dec(hex));

return 0;
}

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM