แปลงถ่านเป็น int ใน C และ C ++


400

ฉันจะแปลงวิธีcharไปยังintใน C และ C ++?


1
@ Matt: มันจะเป็นความคิดที่ดีที่จะเป็นรูปธรรมมากขึ้น ถามเกี่ยวกับการวางนัยทั่วไปเพียงแค่เชิญคำตอบทั่วไปที่ไม่เกี่ยวข้องหรือแม้แต่ถูกต้องสำหรับงานของคุณ โปรดจำไว้เมื่อคุณต้องถามคุณอาจไม่รู้จักพอที่จะพูดคุยอย่างถูกต้อง
ไชโยและ hth - Alf

@Alf P. Steinbach: คำถามเดิมคลุมเครือเกี่ยวกับภาษาใด ด้วยคำหลักcและc++ฉันคิดว่าคำตอบที่เผชิญหน้าทั้งสองภาษานั้นสมเหตุสมผล
Matt Joiner

8
จากประสบการณ์ที่กว้างขวางของฉันในฟอรั่มทางเทคนิคอื่น ๆ ปรีชาของฉันคือ OP จริงๆหมายถึง "ฉันจะใช้การแสดงข้อความของตัวเลข (ในฐาน 10) และแปลงเป็นตัวเลขที่เกี่ยวข้องได้อย่างไร" โดยทั่วไป C และ C ++ สาวกมักจะมีอย่างไม่น่าเชื่อความคิดคลุมเครือเกี่ยวกับวิธีการทำงานในข้อความภาษาเหล่านั้นและสิ่งที่charหมายถึงจริงๆ
Karl Knechtel

3
@KarlKnechtel: ถ้าเป็นเรื่องจริง (ฉันให้ประมาณ 50/50 เนื่องจากมีบทเรียนมากมายก่อนหน้านี้ยังสนับสนุนให้นำค่า ASCII ออกจากตัวอักษรถึงแม้ว่า ASCII จะไม่ครอบคลุมเต็มรูปแบบ) OP ต้องการความชัดเจน - แต่มันก็เป็นคู่หู ของstackoverflow.com/questions/439573/...
Fred Nurk

3
OP มีสามชั่วโมงในการชี้แจงคำถามนี้และไม่สามารถทำได้ ตามที่เป็นอยู่ไม่มีทางรู้ว่าสิ่งที่ถามจริง โหวตให้ปิด
sbi

คำตอบ:


551

ขึ้นอยู่กับสิ่งที่คุณต้องการจะทำ:

เพื่ออ่านค่าเป็นรหัส ASCII คุณสามารถเขียน

char a = 'a';
int ia = (int)a; 
/* note that the int cast is not necessary -- int ia = a would suffice */

การแปลงตัวอักษร'0' -> 0, '1' -> 1ฯลฯ คุณสามารถเขียน

char a = '4';
int ia = a - '0';
/* check here if ia is bounded by 0 and 9 */

คำอธิบาย :
a - '0'เทียบเท่ากับ((int)a) - ((int)'0')ซึ่งหมายความว่าค่า ascii ของตัวละครจะถูกลบออกจากกัน เนื่องจาก0มาก่อน1ในตาราง ascii (และต่อ ๆ ไปเรื่อย ๆ9) ความแตกต่างระหว่างทั้งสองจะให้ตัวเลขที่ตัวละครaแทน


14
ia = (a - '0')% 48;
Kshitij Banerjee

@ KshitijBanerjee นั่นไม่ใช่ความคิดที่ดีสำหรับสองเหตุผล: มันให้ตัวเลขลบสำหรับอักขระ ASCII ก่อนหน้า '0' (เช่น&-> -10) และให้ตัวเลขมากกว่า 10 (เช่นx-> 26)
SheetJS

2
int ia = a - '0' - นั่นคือสิ่งที่คุณต้องการ
ฟังก์

5
@ kevin001 ถ้าคุณต้องการแปลงถ่านเป็น int และตัวอักษร'1'ให้หมายเลข ASCII ที่ไม่ได้1คุณจะต้องลบออฟเซ็ต'0'เพื่อปรับแต่งนับจาก 0-9 ตัวเลขที่ต่อเนื่องกัน 1-9 อยู่ติดกันในจำนวนเต็ม ASCII
krisdestruction

ไม่ต้องการนักแสดง / ต้องการ
Craig Estey

97

ดีในรหัส ASCII ตัวเลข (หลัก) เริ่มต้นจาก48 สิ่งที่คุณต้องทำคือ:

int x = (int)character - 48;

19
@chad: ไม่เพียง แต่อ่านได้มากขึ้น แต่ยังพกพาได้มากกว่า C และ C ++ ไม่รับประกันการเป็นตัวแทน ASCII แต่รับประกันได้ว่าการใช้งานใด ๆ ที่เป็นตัวแทนการแสดงตัวเลขทศนิยม 10 หลักนั้นต่อเนื่องกันและเรียงตามตัวเลข
Ben Voigt

สิ่งเดียวที่ฉันจะเปลี่ยนคือเปิด 48 ซึ่งดูเหมือนว่า "วิเศษ" เป็น'0'
ArielGro

59

C และ C ++ intเสมอส่งเสริมประเภทอย่างน้อย นอกจากนี้ตัวอักษรตัวอักษรเป็นประเภทintใน C และcharC ++

คุณสามารถแปลงชนิดเพียงโดยการกำหนดไปยังcharint

char c = 'a'; // narrowing on C
int a = c;

3
นอกจากนี้คุณยังสามารถใช้อย่างมากภายใต้การชื่นชมเอก operator+()เพื่อวัตถุประสงค์นี้
Cubbi

24
-1 คำตอบนั้นไม่ถูกต้องสำหรับการตีความคำถามที่มีความหมายเท่านั้น (รหัสint a = c;) นี้จะเก็บค่าลบใด ๆ ซึ่งฟังก์ชันไลบรารีมาตรฐาน C ไม่สามารถจัดการได้ ฟังก์ชันไลบรารีมาตรฐาน C ตั้งค่ามาตรฐานสำหรับความหมายของการจัดการcharค่าintต่างๆ
ไชโยและ hth - Alf

6
@ Matt: ฉันรักษา downvote ฉันจะเพิ่มความแข็งแกร่งถ้าเป็นไปได้! การตีความคำถามที่คุณและคนอื่น ๆ สันนิษฐานว่าไม่มีความหมายเพราะมันเป็นเรื่องเล็กน้อยมากและเนื่องจากการผสมผสานประเภทเฉพาะของ OP จึงเป็นประเด็นที่สำคัญมากในทางปฏิบัติ คำแนะนำที่คุณให้นั้นเป็นสิ่งที่อันตรายสำหรับมือใหม่ มันจะส่งผลให้เกิดพฤติกรรมที่ไม่ได้กำหนดสำหรับโปรแกรมที่ใช้ฟังก์ชันการจำแนกประเภทอักขระไลบรารีมาตรฐาน C อ้างอิง ถึงคำตอบของ @ Sayam เขาได้ลบคำตอบนั้น
ไชโยและ hth - Alf

3
-1 สำหรับความไม่ถูกต้อง: isupper () จะมีผลลัพธ์ที่ไม่ได้กำหนดหากผ่านอักขระ highbit 1252
Chris Becke

1
คุณส่งเสริม "เสมอส่งเสริม" หมายความว่าอย่างไร มีการเลื่อนระดับค่าระหว่างการแปลงโดยนัยพารามิเตอร์บางประเภทผ่าน (เช่นไปยังฟังก์ชัน varargs) และเมื่อผู้ประกอบการต้องทำให้ชนิดที่เข้ากันได้ของตัวถูกดำเนินการ แต่มีบางครั้งที่ค่าไม่ได้รับการเลื่อนตำแหน่ง (เช่นถ้าฉันส่งถ่านไปยังฟังก์ชันที่คาดว่าถ่าน) มิฉะนั้นเราจะไม่มีประเภทใดที่เล็กกว่า int
Adrian McCarthy

31

ถ่านเป็นจำนวนเต็ม 1 ไบต์ ไม่มีอะไรวิเศษกับประเภทถ่าน! เช่นเดียวกับที่คุณสามารถกำหนด short ให้กับ int หรือ int ถึง long คุณสามารถกำหนด char ให้กับ int

ใช่ชื่อของชนิดข้อมูลดั้งเดิมเกิดขึ้นเป็น "อักขระ" ซึ่งบอกเป็นนัยว่าควรมีอักขระเท่านั้น แต่ในความเป็นจริง "ถ่าน" เป็นเพียงชื่อที่ไม่ดีเลือกที่จะสร้างความสับสนให้ทุกคนที่พยายามเรียนรู้ภาษา ชื่อที่ดีขึ้นสำหรับมันคือ int8_t และคุณสามารถใช้ชื่อนั้นแทนหากคอมไพเลอร์ของคุณเป็นไปตามมาตรฐาน C ล่าสุด

แม้ว่าแน่นอนคุณควรใช้ประเภทถ่านเมื่อทำการจัดการสตริงเนื่องจากดัชนีของตาราง ASCII แบบคลาสสิกควรมีขนาด 1 ไบต์ อย่างไรก็ตามคุณสามารถจัดการกับสตริงด้วย int ปกติได้เช่นกันแม้ว่าจะไม่มีเหตุผลในทางปฏิบัติในโลกแห่งความจริงว่าทำไมคุณถึงอยากทำเช่นนั้น ตัวอย่างเช่นรหัสต่อไปนี้จะทำงานได้อย่างสมบูรณ์:

  int str[] = {'h', 'e', 'l', 'l', 'o', '\0' };

  for(i=0; i<6; i++)
  {
    printf("%c", str[i]);
  }

คุณต้องตระหนักว่าตัวอักษรและสตริงเป็นเพียงตัวเลขเช่นทุกอย่างในคอมพิวเตอร์ เมื่อคุณเขียน 'a' ในซอร์สโค้ดมันจะถูกประมวลผลล่วงหน้าเป็นหมายเลข 97 ซึ่งเป็นค่าคงที่จำนวนเต็ม

ดังนั้นถ้าคุณเขียนนิพจน์เช่นนั้น

char ch = '5';
ch = ch - '0';

นี่เทียบเท่ากับ

char ch = (int)53;
ch = ch - (int)48;

ซึ่งจะผ่านการโปรโมตจำนวนเต็มภาษา C

ch = (int)ch - (int)48;

และตัดให้เป็นอักขระเพื่อให้พอดีกับประเภทผลลัพธ์

ch = (char)( (int)ch - (int)48 );

มีหลายสิ่งที่ละเอียดอ่อนเช่นนี้เกิดขึ้นระหว่างบรรทัดที่ซึ่งถ่านถูกถือว่าเป็น int โดยปริยาย


เนื่องจากไม่ได้ติดแท็กคำถามไว้asciiคุณไม่ควรใช้การเข้ารหัสเฉพาะใด ๆ การตั้งค่าcharเท่ากับint8_tผิดเพราะมันอาจจะมีแนวโน้มที่จะเท่าเทียมกันหรือuint8_t uint24_t
Roland Illig

1
@RolandIllig No, a charเป็น 1 ไบต์เสมอและหากประเภทint8_t/ uint8_tมีอยู่ในระบบที่กำหนด (ซึ่งมีแนวโน้มมาก) พวกเขาจะสามารถพอดีกับผลลัพธ์ของ a charเพราะมันจะเป็น 8 บิต สำหรับระบบที่แปลกใหม่อย่างเช่น DSP ที่ล้าสมัยหลายรุ่นcharจะเป็น 16 บิตและuint8_tจะไม่มีอยู่จริง การเขียนรหัสเพื่อความเข้ากันได้กับ DSP ที่ล้าสมัยนั้นไร้สาระเช่นเดียวกับการเขียนเพื่อความเข้ากันได้กับระบบประกอบหรือระบบสัญญาณและขนาด เสียเวลามากเนื่องจากระบบดังกล่าวแทบจะไม่มีอยู่จริงในโลกแห่งความเป็นจริง
Lundin

18

(คำตอบนี้ระบุถึงด้าน C ++ ของสิ่งต่าง ๆ แต่ปัญหาส่วนขยายของสัญญาณมีอยู่ใน C ด้วยเช่นกัน)

การจัดการทั้งสามcharประเภท ( signed, unsignedและchar) มีความละเอียดอ่อนกว่าที่ปรากฏก่อน ค่าในช่วง 0 ถึงSCHAR_MAX(ซึ่ง 127 สำหรับ 8 บิตchar) นั้นง่าย:

char c = somevalue;
signed char sc = c;
unsigned char uc = c;
int n = c;

แต่เมื่อsomevalueอยู่นอกช่วงนั้นการผ่านไปเท่านั้นจะunsigned charให้ผลลัพธ์ที่สอดคล้องกันสำหรับค่า "เดียวกัน" charในทั้งสามประเภท:

char c = somevalue;
signed char sc = c;
unsigned char uc = c;
// Might not be true: int(c) == int(sc) and int(c) == int(uc).
int nc = (unsigned char)c;
int nsc = (unsigned char)sc;
int nuc = (unsigned char)uc;
// Always true: nc == nsc and nc == nuc.

สิ่งนี้มีความสำคัญเมื่อใช้ฟังก์ชันจากctype.hเช่นisupperหรือtoupperเนื่องจากส่วนขยายสัญญาณ:

char c = negative_char;  // Assuming CHAR_MIN < 0.
int n = c;
bool b = isupper(n);  // Undefined behavior.

หมายเหตุการแปลงผ่าน int นั้นเป็นนัย สิ่งนี้มี UB เดียวกัน:

char c = negative_char;
bool b = isupper(c);

เพื่อแก้ไขปัญหานี้ผ่านไปunsigned charซึ่งจะกระทำได้ง่ายโดยการตัดctype.hฟังก์ชั่นผ่านsafe_ctype :

template<int (&F)(int)>
int safe_ctype(unsigned char c) { return F(c); }

//...
char c = CHAR_MIN;
bool b = safe_ctype<isupper>(c);  // No UB.

std::string s = "value that may contain negative chars; e.g. user input";
std::transform(s.begin(), s.end(), s.begin(), &safe_ctype<toupper>);
// Must wrap toupper to eliminate UB in this case, you can't cast
// to unsigned char because the function is called inside transform.

สิ่งนี้ได้ผลเพราะฟังก์ชั่นใด ๆ ที่ใช้ถ่านประเภทใดประเภทหนึ่งในสามชนิดก็สามารถใช้ถ่านประเภทอื่นได้อีกสองชนิด มันนำไปสู่สองฟังก์ชั่นที่สามารถจัดการประเภทใด ๆ :

int ord(char c) { return (unsigned char)c; }
char chr(int n) {
  assert(0 <= n);  // Or other error-/sanity-checking.
  assert(n <= UCHAR_MAX);
  return (unsigned char)n;
}

// Ord and chr are named to match similar functions in other languages
// and libraries.

ord(c)มักจะช่วยให้คุณมีค่าที่ไม่ใช่เชิงลบ - แม้เมื่อผ่านเชิงลบcharหรือเชิงลบsigned char- และchrต้องใช้ค่าใด ๆผลิตและให้กลับเดียวกันแน่นอนordchar

ในทางปฏิบัติผมจะอาจจะเพียงแค่โยนผ่านunsigned charแทนการใช้เหล่านี้ แต่พวกเขาไม่ชัดถ้อยชัดคำห่อโยนให้เป็นสถานที่ที่สะดวกในการเพิ่มการตรวจสอบข้อผิดพลาดสำหรับint-to- charและจะสั้นและชัดเจนมากขึ้นเมื่อคุณจำเป็นต้องใช้พวกเขาหลายต่อหลายครั้ง ในบริเวณใกล้เคียง



7

มันขึ้นอยู่กับสิ่งที่คุณหมายถึงโดย "แปลง"

หากคุณมีชุดอักขระที่แสดงถึงจำนวนเต็มเช่น "123456" มีวิธีทั่วไปสองวิธีใน C: ใช้การแปลงเพื่อวัตถุประสงค์พิเศษเช่นatoi ()หรือstrtol ()หรือsscanf สำหรับวัตถุประสงค์ทั่วไป() C ++ (ซึ่งเป็นภาษาอื่นที่ปลอมแปลงเป็นอัพเกรด) เพิ่มสตริงที่สาม

หากคุณหมายความว่าคุณต้องการรูปแบบบิตที่แน่นอนหนึ่งในของintตัวแปรที่จะได้รับการปฏิบัติในฐานะcharที่ง่ายขึ้น ใน C ประเภทจำนวนเต็มที่แตกต่างกันเป็นสถานะของจิตใจที่ดีกว่า "ประเภท" ที่แยกต่างหากจริง เพียงแค่เริ่มใช้มันในที่ที่charถูกขอและคุณควรจะตกลง คุณอาจต้องมีการแปลงที่ชัดเจนเพื่อให้คอมไพเลอร์หยุดเสียงหอนในบางโอกาส แต่สิ่งที่ควรทำคือปล่อยบิตพิเศษใด ๆ ที่ผ่านมา 256


6

ฉันมีnullทักษะอย่างC แต่สำหรับการแยกง่าย ๆ :

char* something = "123456";

int number = parseInt(something);

... สิ่งนี้ได้ผลกับฉัน:

int parseInt(char* chars)
{
    int sum = 0;
    int len = strlen(chars);
    for (int x = 0; x < len; x++)
    {
        int n = chars[len - (x + 1)] - '0';
        sum = sum + powInt(n, x);
    }
    return sum;
}

int powInt(int x, int y)
{
    for (int i = 0; i < y; i++)
    {
        x *= 10;
    }
    return x;
}

รหัสนี้เรียกใช้ลักษณะการทำงานที่ไม่ได้กำหนดอย่างรวดเร็วดังนั้นจึงไม่เหมาะสำหรับการคัดลอกและการวาง (ล้นมากเกิน)
Roland Illig

4

สมมุติว่าคุณต้องการให้การแปลงนี้ใช้ฟังก์ชั่นจากไลบรารีมาตรฐาน C

ในกรณีนั้นให้ทำ (ไวยากรณ์ C ++)

typedef unsigned char UChar;

char myCppFunc( char c )
{
    return char( someCFunc( UChar( c ) ) );
}

นิพจน์UChar( c )แปลงเป็นunsigned charเพื่อกำจัดค่าลบซึ่งยกเว้น EOF ซึ่งฟังก์ชั่น C ไม่รองรับ

จากนั้นผลลัพธ์ของนิพจน์นั้นจะใช้เป็นอาร์กิวเมนต์จริงสำหรับอาร์กิวเมนต์ที่เป็นintทางการ คุณจะได้รับโปรโมชันอัตโนมัติจากintที่ไหน หรือคุณสามารถเขียนขั้นตอนสุดท้ายอย่างชัดเจนเช่นint( UChar( c ) )แต่โดยส่วนตัวแล้วฉันพบว่า verbose มากเกินไป

ไชโย &


0

ฉันมีปัญหาในการแปลงอาร์เรย์ char เหมือน"7c7c7d7d7d7d7c7c7c7d7d7d7d7c7c7c7c7c7c7d7d7c7c7c7c7d7c7d7d7d7c7c2e2e2e"เป็นค่าจำนวนเต็มที่แท้จริงที่จะสามารถแสดงด้วย '7C' เป็นค่าเลขฐานสิบหกหนึ่ง ดังนั้นหลังจากล่องเรือเพื่อขอความช่วยเหลือฉันสร้างมันขึ้นมาและคิดว่ามันคงเจ๋งที่จะแบ่งปัน

สิ่งนี้จะแยกสตริงอักขระ char ออกเป็นจำนวนเต็มที่ถูกต้องและอาจเป็นประโยชน์กับคนมากกว่าฉัน;)

unsigned int* char2int(char *a, int len)
{
    int i,u;
    unsigned int *val = malloc(len*sizeof(unsigned long));

    for(i=0,u=0;i<len;i++){
        if(i%2==0){
            if(a[i] <= 57)
                val[u] = (a[i]-50)<<4;
            else
                val[u] = (a[i]-55)<<4;
        }
        else{
            if(a[i] <= 57)
                val[u] += (a[i]-50);
            else
                val[u] += (a[i]-55);
            u++;
        }
    }
    return val;
}

หวังว่ามันจะช่วย!


คุณเคยทดสอบโค้ดนี้หรือไม่? 50 ควรเป็น 48, 55 ใช้สำหรับตัวอักษร ASCII ตัวพิมพ์ใหญ่เท่านั้นในขณะที่ตัวอย่างของคุณมีตัวอักษรตัวเล็ก
Roland Illig

0

สำหรับอักขระถ่านหรือสั้นถึง int คุณเพียงแค่ต้องกำหนดค่า

char ch = 16;
int in = ch;

เช่นเดียวกันกับ int64

long long lo = ch;

ค่าทั้งหมดจะเป็น 16


-1
int charToint(char a){
char *p = &a;
int k = atoi(p);
return k;
}

คุณสามารถใช้วิธีนี้ atoi สำหรับการแปลงถ่านเป็น int สำหรับข้อมูลเพิ่มเติมคุณสามารถอ้างถึงนี้http://www.cplusplus.com/reference/cstdlib/atoi/ , http://www.cplusplus.com/reference/string/stoi/


1
นี่คือพฤติกรรมที่ไม่ได้กำหนด การระบุที่อยู่ของตัวแปร char จะให้ char * แต่ไม่ใช่ C-string ซึ่งเป็นสิ่งที่ atoi คาดหวัง
luizfls
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.