我正在研究K& R的C编程语言,并且有一个练习如下:
练习3-5:编写将整数n转换为字符串s中的基本b字符表示的函数itob(n,s,b)。特别是,itob(n,s,16)将n格式化为s中的十六进制整数。
所以我写了这样的程序:
#include <stdio.h>
#include <string.h>
#define MAXLINE 1000
void reverse(char );
void itob(int , char , int );
main()
{
char line[MAXLINE];
int n, i;
printf("integer: ");
scanf_s("%d",&n);
printf("base: ");
scanf_s("%d",&i);
itob(n, line, i);
printf("%s", line);
}
void itob(int n, char s[], int b)
{
int i, sign;
if ((sign = n) < 0)
n = -n;
i = 0;
do
{
n % b < 10 ? (s[i++] = n % b + '0') : (s[i++] = n % b + '7');
}
while ((n /= b) > 0);
if (sign < 0)
s[i++] = '-';
s[i] = '\0';
reverse(s);
}
void reverse(char s[])
{
int c, i, j;
for (i = 0, j = strlen(s)-1; i < j; i++, j--)
{
c = s[i];
s[i] = s[j];
s[j] = c;
}
}
我觉得一切都还好。但是当我运行程序时,输入整数和基数值后出现错误,如下所示:
练习3-5.exe中0x10022050(msvcr110d.dll)的未处理异常: 0xC0000005:访问冲突读取位置0x000000EC。
因此该程序在功能itob调用时遇到了问题。
然后经过大约2个小时的调试,我发现原因是反向的功能原型需要包含这样的参数名称:
void reverse(char s[]);
void itob(int , char , int );
我做的唯一改变是在反向函数原型中添加了s [],然后程序正常工作。
我很困惑,因为我学到的只是函数原型的参数名是可选的。为什么参数名称必须包含在反向函数原型中?为什么itob的函数原型不需要参数名称而且没有弹出错误?我的IDE是Visual Studio 2012.
感谢大家的时间和帮助。
答案 0 :(得分:2)
你问题中的代码有很多错误,其中许多错误都是你的编译器应该至少警告你的。
当我复制代码并使用gcc编译它时,即使没有任何其他参数,第一条错误信息是:
c.c: In function ‘main’:
c.c:16:5: warning: passing argument 2 of ‘itob’ makes integer from pointer without a cast [enabled by default]
itob(n, line, i);
^
c.c:6:6: note: expected ‘char’ but argument is of type ‘char *’
void itob(int , char , int );
^
错误消息是正确的。您使用类型为itob
的第二个参数声明了char
,然后使用类型为char*
的第二个参数调用它(由数组line
的隐式转换产生)。 / p>
稍后,您使用类型为itob
的第二个参数定义 char[]
(因为它是一个参数,实际上属于char*
类型)。这与之前的声明不兼容,它也应该由编译器标记。
要回答标题中的问题,在独立原型(不属于函数定义的原型)中,参数名称是可选的。这两个原型是等效且有效的:
void itob(int, char, int);
和
void itob(int x, char y, int z);
我个人喜欢指定参数名称只是因为它使代码更清晰。
对于作为函数定义一部分的原型,名称是必需的,因为这是参数对象的定义方式。
但首先,修复代码中的错误。