2014-10-20 42 views
1

我是一名中级Python程序员,但我正在努力学习C.迄今为止,这是一个非常令人沮丧的经历。为什么printf在我的简单脚本中产生奇怪的输出?

为什么这个简单的代码...

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

char name[15] = "George Lopez"; /* string representing your name */ 
char birthday[6] = "01-30-92"; /* string representing your bday */ 
int phone_number; /* declair int representing phone number */ 

int main() { 
    phone_number = 2222223333; /* int representing your phone number */ 
    printf("You said your name was: %s\n", name); 
    printf("And your birthday is %s?\n", birthday); 
    printf("And, so I can call you, your number is %d\n", phone_number); 
    return(0); /* exit program normally */ 
} 

产生这种输出时的电话号码是2222223333:

You said your name was: George Lopez 
And your birthday is 01-30-92? 
And, so I can call you, your number is -2072743963 

,该输出将电话号码为9992223333:

error: 4_1_myinfo.c:16:3: warning: overflow in implicit constant conversion [-Woverflow] 
    phonenumber = 9992223333; 

而这个输出当电话号码是1112223333:

You said your name was: George Lopez 
And your birthday is 01-30-92? 
And, so I can call you, your number is 1112223333 

我怀疑这跟下用整数如何交易的事情。也许,C中的ints的最大长度比python中的ints小,这导致了wanky输出?

+5

超出数组范围:'char birthday [6] =“01-30-92”;',导致未定义的行为。 – hmjd 2014-10-20 16:37:20

+0

'生日'应该会导致编译时的强制性诊断。如果你(可以做)忽略它,它不是一个有效的字符串,所以将它作为字符串传递给'printf'就是UB。 – Deduplicator 2014-10-20 16:41:00

+0

尽管它表示为一串数字,但电话号码并非真正的数字。也使用一个字符串。 – chepner 2014-10-20 16:45:18

回答

3

这里有几个主要问题。

首先,使用C-字符串时,避免定义如果可以在所述缓冲器的大小,像这样:

char name[] = "George Lopez"; /* string representing your name */ 
char birthday[] = "01-30-92"; /* string representing your bday */ 

如果必须预先定义的最大字符串长度,使用共同的限制,像所以:

#define MAX_STR_LEN 256 
char name[MAX_STR_LEN] = "George Lopez"; /* string representing your name */ 
char birthday[MAX_STR_LEN] = "01-30-92"; /* string representing your bday */ 

如果你没有在未来对其进行修改计划,使他们const像这样:

const char* name = "George Lopez"; /* string representing your name */ 
const char* birthday = "01-30-92"; /* string representing your bday */ 

在你的情况中,你定义了一个只能容纳6个字符的字符数组,但是试图填充9个字符“01-30-92”,加上尾随的\0字符自动包含。大错。

的第二个主要问题是,你正试图适应字面到不能保持它的数据类型的整数。在C中,最大带符号32位值2,147,483,647<limits.h>中定义为INT_MAX。你应该让你的代码如下所示:

长的长整型PHONE_NUMBER = 2222222222L;

通知后数字文字后缀,L?这是为了让你的代码能够编译,并且使用long long int来创建一个实际上可以存储这个值的变量是必要的。

最后,你应该考虑使用字符串来保存电话号码。你没有对它进行任何代数/数学操作,所以不需要使用整数数据类型来表示它。

代码(修改)


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

char name[] = "George Lopez"; /* string representing your name */ 
char birthday[] = "01-30-92"; /* string representing your bday */ 
long long int phone_number; /* declair int representing phone number */ 

int main() { 
    phone_number = 2222223333L; /* int representing your phone number */ 
    printf("You said your name was: %s\n", name); 
    printf("And your birthday is %s?\n", birthday); 
    printf("And, so I can call you, your number is %lld\n", phone_number); 
    return(0); /* exit program normally */ 
} 

样本输出


You said your name was: George Lopez 
And your birthday is 01-30-92? 
And, so I can call you, your number is 2222223333 
+0

从数组移动到指针的错误想法。顺便说一句,你为什么不让指针保持不变? – Deduplicator 2014-10-20 16:46:15

+0

@Deduplicator如果数据只是只读的,指针方法非常好。不需要使指针“const”也是必需的。这只是保存的数据,而不是指针本身。 – DevNull 2014-10-20 16:49:40

+0

那无谓的间接(和额外的变量)给你买了什么? (如果它是'static const',可能会有一些用处,尽管这是有争议的)。另外,我确定你想为'long long'而不是'L'指定后缀'LL'。 – Deduplicator 2014-10-20 16:52:04

0

在C中,所有的数据类型都有固定的大小。通常一个int是一个32位值(但不一定是),所以它的最大值为2,147,483,647。

你的价值,9992223333超过此值,它为什么你得到一个警告。你需要使用一个更大的数据类型,比如64位数字。如果您使用的是Windows,这通常是long long,如果您使用的是Linux,则通常使用long

+1

甚至更​​好地使用uint64_t作为平台独立。它在stdint.h中定义,并且与C99兼容。 – 2014-10-20 16:42:28

1

我认为处理电话号码的更好方法是将它们视为一个字符串。您需要一个字符串类型来“格式化”输出,并且在考虑用户输入时验证电话号码是否遵循某个“正则表达式”。

0

为了理解为什么发生这种情况,你需要了解的数字是如何在记忆中表示。我会尽量让你看到他们工作的基本方式,以及一些有兴趣的参考资料。由于计算机只能理解0和1,因此基数2是明显的选择。但是,代表负数存在问题。有一些表示,如符号幅度表示(基本上,有一点代表符号 - 如果它被设置,数字是负数),这是非常简单的。问题是这种表示有两种表示0的方式:+0和-0。所以,一个聪明的表示,被称为二进制补码被使用。对于二进制数abcd(其中a,b,c,d代表其位数),基10的值为a * 2^3 + b * 2^2 + c * 2^1 + d * 2^0。如果这个数是2的补码4位表示,则其基数为10的值将是-a * 2^3 + b * 2^2 + c * 2^1 + d * 2^0。所以,在二进制补码中,第一个比特具有负的权重。在4位二进制补码表示中,如果你有0111(十进制7)并且你尝试加1,那么你将得到1000,即-8。这被称为溢出。只有在相同符号中添加数字并获得不同符号的结果时才会出现溢出(将两个正数相加成负数或将两个负数相加得到正数)。

在你的程序中,会发生类似的事情。唯一的区别是,INT具有32位,而不是4。

更多参考: http://en.wikipedia.org/wiki/Binary_number http://en.wikipedia.org/wiki/Signed_number_representations

0

一个符号的32位整数的范围是[-2147483648 2147483647]。您尝试将您的电话号码表示为有符号整数。

a. When phone num is 1112223333, it's less than the max 2147483647, so you get theright output. 

b. 2222223333 is greater than the max 2147483647, but can still be represented as a 32-bit number, you get the 2's complement number which is -2072743963 

c. 9992223333 cannot be represented by a 32-bit number, i.e. it's even bigger than (2^32 - 1), that's why you such error.