C中基本转换时的分段错误
Segmentation fault at base converting in C
正在尝试将 dec 转换为 32 进制,然后将其打印到文件中。
const char digits[] = "0123456789ABCDEFGHIJKLMNOPQRSTUV";
char* baseConverter(int num, int base)
{ char* res;
int i=0;
if (num == 0 || base == 10)
{
snprintf(res,"%03x",num);
return *res;
}
while( num > 0 )
{
*(res+i) = digits[num%base];
num=num/base;
}
return *res;
}
然后在输出代码处:
sprintf(line, "%03s", baseConverter(i, 32);
但我一直在 运行 收到 Segmentation fault (core dumped)
错误。
这里发生了几件事:
- 首先,一个未初始化的本地指针有一个不确定的值;它没有特别指向任何地方。
NULL
指针也不指向任何地方,但至少您可以轻松地测试 NULL
指针。养成初始化指针的习惯,使其指向有效的内存或使其明确为空。
- 指针应该指向一个字符缓冲区。您的函数看起来像这样,您必须使用
malloc
为堆上的缓冲区分配内存。 (您不能使用本地存储,因为它会立即失效。)
- 不要以 10 为底数作为特例。 (您甚至将以 10 为底的数字打印为十六进制,这也是错误的。)
- 你的打印方式没问题,但是你把数字打印反了。所以先确定需要的klength,再把你打印的位置减1。
- 在这里,您处理原始字符。使用
res[i]
而不是使用标准库函数做复杂的事情。特别是,不要通过连接或打印字符串来构建字符串。这很可能是未定义的行为。
您的函数的可能实现如下所示:
int ndigits(int num, int base)
{
int n = 0;
while (num) {
n++;
num /= base;
}
if (n == 0) n++;
return n;
}
char* baseConverter(int num, int base)
{
if (num >= 0 && base > 1 && base <= 36) {
int n = ndigits(num, base);
char *res = malloc(n + 1);
int i = n;
res[n] = '[=10=]';
if (num == 0) res[--i] = '0';
while (num) {
res[--i] = digits[num % base];
num /= base;
}
return res;
}
return NULL;
}
注意如何使用辅助函数来确定字符串的长度。然后向后填充字符串,以空终止符开始。另请注意如何通过返回 NULL
.
来处理无效案例
您的调用代码必须在使用后显式释放该字符串:
int n = rand() % 100000 + 1;
int m = rand() % 10 + 2;
char *p = baseConverter(n, m);
if (p) printf("%d#%d == %s\n", n, m, p);
free(p);
C 有手动内存管理,跟踪分配的东西很乏味。例如,您不能从 printf
内部调用 baseConverter
,因为您会丢失已分配字符串的句柄。
另一种流行的变体是让调用代码分配内存,然后将缓冲区及其大小传递给函数以填充它。原型可能如下所示:
void sbase(char buf, size_t buflen, int num, int base);
然后会这样调用:
char buf[33]; // Maximum, when base 2 is printed
sbase(buf, sizeof(buf), 5000, 13);
puts(buf);
因为buf
是一个自动变量,所以不需要free
ing。 (如何实施 thins 以及如何正确强制不超过缓冲区大小留作练习。:)
)
主要错误已经指出。
这是另一个建议的例程(它不需要 malloc)
该函数将指针的值设置为转换后的位数,以便于打印出所需的位数。
#include <stdio.h>
/* function takes pointer to array, size of array + number/base
and pointer for number of digits in conversion */
void make32(int *res32, int len, int num, int base, int *rln);
int main()
{
int digits32[20]; // size according to max conversion number in base 32
int len32 = sizeof(digits32)/sizeof(digits32[0]);
int in32, resln, n;
/* convert this number */
in32 = 10000;
/* call function with pointer + size & number/base & ptr to # converted digits*/
make32(digits32, len32, in32, 32, &resln);
/* print out result - reverse order - use number of digits */
for(n = resln; n >= 0; n--) {
printf("%d ", digits32[n]);
}
printf("\n");
return (0);
}
void make32(int *res32, int len, int num, int base, int *rln)
{
int i = 0;
while( num > 0 && i <= len ) {
res32[i] = num % base;
num = num / base;
i++;
}
/* set the number of converted digits */
*rln = i - 1;
}
正在尝试将 dec 转换为 32 进制,然后将其打印到文件中。
const char digits[] = "0123456789ABCDEFGHIJKLMNOPQRSTUV";
char* baseConverter(int num, int base)
{ char* res;
int i=0;
if (num == 0 || base == 10)
{
snprintf(res,"%03x",num);
return *res;
}
while( num > 0 )
{
*(res+i) = digits[num%base];
num=num/base;
}
return *res;
}
然后在输出代码处:
sprintf(line, "%03s", baseConverter(i, 32);
但我一直在 运行 收到 Segmentation fault (core dumped)
错误。
这里发生了几件事:
- 首先,一个未初始化的本地指针有一个不确定的值;它没有特别指向任何地方。
NULL
指针也不指向任何地方,但至少您可以轻松地测试NULL
指针。养成初始化指针的习惯,使其指向有效的内存或使其明确为空。 - 指针应该指向一个字符缓冲区。您的函数看起来像这样,您必须使用
malloc
为堆上的缓冲区分配内存。 (您不能使用本地存储,因为它会立即失效。) - 不要以 10 为底数作为特例。 (您甚至将以 10 为底的数字打印为十六进制,这也是错误的。)
- 你的打印方式没问题,但是你把数字打印反了。所以先确定需要的klength,再把你打印的位置减1。
- 在这里,您处理原始字符。使用
res[i]
而不是使用标准库函数做复杂的事情。特别是,不要通过连接或打印字符串来构建字符串。这很可能是未定义的行为。
您的函数的可能实现如下所示:
int ndigits(int num, int base)
{
int n = 0;
while (num) {
n++;
num /= base;
}
if (n == 0) n++;
return n;
}
char* baseConverter(int num, int base)
{
if (num >= 0 && base > 1 && base <= 36) {
int n = ndigits(num, base);
char *res = malloc(n + 1);
int i = n;
res[n] = '[=10=]';
if (num == 0) res[--i] = '0';
while (num) {
res[--i] = digits[num % base];
num /= base;
}
return res;
}
return NULL;
}
注意如何使用辅助函数来确定字符串的长度。然后向后填充字符串,以空终止符开始。另请注意如何通过返回 NULL
.
您的调用代码必须在使用后显式释放该字符串:
int n = rand() % 100000 + 1;
int m = rand() % 10 + 2;
char *p = baseConverter(n, m);
if (p) printf("%d#%d == %s\n", n, m, p);
free(p);
C 有手动内存管理,跟踪分配的东西很乏味。例如,您不能从 printf
内部调用 baseConverter
,因为您会丢失已分配字符串的句柄。
另一种流行的变体是让调用代码分配内存,然后将缓冲区及其大小传递给函数以填充它。原型可能如下所示:
void sbase(char buf, size_t buflen, int num, int base);
然后会这样调用:
char buf[33]; // Maximum, when base 2 is printed
sbase(buf, sizeof(buf), 5000, 13);
puts(buf);
因为buf
是一个自动变量,所以不需要free
ing。 (如何实施 thins 以及如何正确强制不超过缓冲区大小留作练习。:)
)
主要错误已经指出。 这是另一个建议的例程(它不需要 malloc) 该函数将指针的值设置为转换后的位数,以便于打印出所需的位数。
#include <stdio.h>
/* function takes pointer to array, size of array + number/base
and pointer for number of digits in conversion */
void make32(int *res32, int len, int num, int base, int *rln);
int main()
{
int digits32[20]; // size according to max conversion number in base 32
int len32 = sizeof(digits32)/sizeof(digits32[0]);
int in32, resln, n;
/* convert this number */
in32 = 10000;
/* call function with pointer + size & number/base & ptr to # converted digits*/
make32(digits32, len32, in32, 32, &resln);
/* print out result - reverse order - use number of digits */
for(n = resln; n >= 0; n--) {
printf("%d ", digits32[n]);
}
printf("\n");
return (0);
}
void make32(int *res32, int len, int num, int base, int *rln)
{
int i = 0;
while( num > 0 && i <= len ) {
res32[i] = num % base;
num = num / base;
i++;
}
/* set the number of converted digits */
*rln = i - 1;
}