0

这周刚学了C。我的任务是从用户那里获取一个大整数输入,将其存储到一个结构整数中,然后创建一个函数来将适当的结构整数打印到标准输出中。该程序是这样工作的,但是一旦它给出输出,它就会停止响应。我在编译器中没有得到任何直接错误,也无法找出问题所在。任何其他改进编程风格的建议/技巧也将不胜感激:)

// Header Files Go Here
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

// Function Declarations Go Here
struct integer * convert_integer(char * stringInt);
void printer(struct integer * p);

struct integer {
    int * arr;
    int length;
};

// Main Program
int main() {
    char * x;
    x = (char *) malloc(sizeof(char) * 10000);
    printf("Enter a small string\n");
    scanf("%s",x);
    int j = 0;
    struct integer * book1;
    book1 = convert_integer(x);
    printer(book1);
    return 0;
}

// Function Definitions Go Here  
struct integer * convert_integer(char * stringInt) {
    struct integer * x = malloc(sizeof(int) * 100);
    int j = 0;
    while (stringInt[j] != '\0') {
        if (stringInt[j] < 48 || stringInt[j] >= 57) {
            printf("Invalid input. Enter a number ");
            return;
        }
        x->arr[j] = stringInt[j] - 48;
        j++;
    }
    x->length = j;
    printf("\n the length is %d\n", x->length);
    return x;
}

void printer(struct integer * p) {
    int j = 0;
    while (j < p->length) {
        printf("%d", p->arr[j]);
        j++;
    }
}
4

5 回答 5

2

我添加这个答案是因为 NPE 不够清楚。


该程序中存在一些错误,但我会说紧迫的错误在函数中convert_integer。您正在执行以下操作:

struct integer* x= malloc(sizeof(int) * 100);

...但这是不正确的。您请求了太多字节的内存来x考虑其数据类型(这并没有什么问题),但是您并没有为arr. 它需要如下所示:

struct integer *x = malloc( sizeof( struct integer ) );

x->arr = malloc( sizeof( int ) * c );

...c一些常数在哪里(在你的情况下是100?)。确保当你创建free这个结构时,你首先是free结构,否则你将有内存泄漏。arrfree

我注意到你没有做的其他事情,总是检查系统调用的结果。您没有检查是否malloc返回了无效的内存块。

于 2013-08-10T14:22:23.987 回答
0

您需要printer在顶部添加一个原型。验证数字的if语句应该是

if(stringInt[j]<48 || stringInt[j]>57)  // > instead of >=

写成这样会更有意义

if ( stringInt[j] < '0' || stringInt[j] > '9' )

如果你知道isdigit函数,你也可以使用它。

您正在为 10000 个字符的字符串分配内存。这似乎是矫枉过正。您可以为 256 个字符分配内存,这应该足够了。return您还应该在使用语句执行之前释放内存free (x);

您需要为函数arr内部分配空间convert_integer。你的分配应该是:

struct integer* x= malloc(sizeof(integer)); x->arr = malloc ( sizeof(int) * 256 );
于 2013-08-10T14:02:11.823 回答
0

这里:

struct integer* x= malloc(sizeof(int) * 100);;

您正在为结构(即指针和 int)分配内存,而不是为数组分配内存。

在您尝试分配给的那一刻x->arr[j],您有未定义的行为

于 2013-08-10T14:04:16.230 回答
0

您的代码失败了

x->arr[j]=stringInt[j]-48;

原因是您分配内存片的方式:

struct integer* x= malloc(sizeof(int) * 100);

这会分配一个n*100字节切片并将指向该切片的指针存储在x. 您想要做的是以下内容:

struct integer *x = malloc(sizeof(*x));
x->arr = malloc(sizeof(int)*100);

这分配了存储integer结构所需的内存x,并分配内存来存储 100 个整数并将其分配给x->arr. 使用您的代码,x->arr未初始化,因此其中包含随机值(更准确地说:这些值是之前存储在该内存位置的值)。

使用完分配的内存后,您还应该释放它:

free(x->arr);
free(x);
于 2013-08-10T14:18:52.720 回答
0

既然您也提出了建议,我将展示一个风格更好的解决方案。

struct Integer {
    unsigned char *array; /* no point storing sign info on each element */
    size_t capacity; /* how many we have space for */
    size_t count;    /* how many we've actually used */
    char sign;       /* +1 or -1 */
};

我在这里做了一些改变:

  1. 数组中每个元素只存储一个以 10 为基数的数字,所以char足够大
  2. 在每个数组元素中存储整数的符号是​​没有用的,所以我unsigned char在外部使用并保留符号
  3. 使您的数组固定大小是不灵活的,并且不是真正的大整数精神。如果你要动态增长它,为每个数字做它很快就会变得昂贵,所以我使用摊销的常数时间技巧,每次它填满它的容量就翻一番

现在,在我们开始使用整数之前,我们需要分配它。现在让我们做最简单的事情,并从零大小开始:

struct Integer *alloc_integer() {
    struct Integer *i = malloc(sizeof(*i));
    /* this integer is empty until we use it ... */
    i->array = NULL;
    i->capacity = 0;
    i->count = 0;
    i->sign = 1;
    return i;
}

当然,如果它保持零大小是没有用的,所以我们需要一些方法来让它更大:

void grow_integer(struct Integer *i, size_t min_size) {
    /* this check is redundant if we're only called from append_integer */
    if (min_size <= i->capacity) return;
    /* jump to the next power of 2 (ie, we usually double the capacity) */
    size_t new_size = i->capacity * 2;
    while (new_size < min_size) new_size *= 2;

    unsigned char *new_array = malloc(new_size * sizeof(*new_array));
    /* figure out how to cope if we run out of memory */

    memcpy(new_array, i->array, i->count * sizeof(*new_array));
    free(i->array);
    i->array = new_array;
    i->capacity = new_size;
}

现在我们可以看到如何附加一个整数:

void append_integer(struct Integer *i, char digit) {
    if (i->count == i->capacity)
        grow_integer(i, i->capacity + 1);
    i->array[ i->count++ ] = (unsigned char)digit;
}

(请注意签入grow_integerappend_integer重叠:我可以删除一个,但我还没有决定是否grow_integer是公共接口)

最后,读取字符串应该很容易:

struct Integer *str_to_Integer(const char *str) {
    struct Integer *i = alloc_integer();
    for (; *str; ++str) {
        if (!isdigit(*str)) {
            free_integer(i);
            return NULL;
        }
        append_integer(i, *str - '0');
    }
    return i;
}

请注意,我使用isdigit并且更喜欢'0'to 48,因为我认为当编译器可以为您执行此操作时,强迫人们记住 ASCII 代码值没有任何真正的好处。

于 2013-08-11T08:52:30.483 回答