简体   繁体   English

如何使用 char * 到 int 转换来纠正分段错误

[英]How to correct segmentation fault with char * to int conversion

ive written the following as a program in order to convert a pointer with a sequence of integers as its adress into an integer number:我编写了以下程序,以便将具有整数序列作为地址的指针转换为整数:

#include <math.h>
#include <stdio.h>

char *recepcao() { char *receber;
    scanf("%s", receber);
    return receber;
}
int conversao(char *string) { int i, j;
    for(i=0; string[i]!='\0'; ++i) {
        continue;
    }
    int *var;
    int contagem=0;
    for(j=0; j<i-1; ++j) {
        var[j]=(string[j]-'0');
        contagem+=var[j]*pow(10, (i-j-1));
    }

    return contagem;
}
int main() {
    printf("%i", conversao(recepcao())); return 0;
}

I've tried about a thousand times to correct all the loops, but still after recieving the scanf value the program would crash, as stated on some IDEs, and would display a "Segmentation Fault: 11" message on others.我已经尝试了大约一千次来纠正所有循环,但是在收到 scanf 值后,程序仍然会崩溃,如某些 IDE 所述,并且会在其他 IDE 上显示“分段错误:11”消息。 How can I fix this?我怎样才能解决这个问题? what is the proper definition of that message?该消息的正确定义是什么?

receber is an uninitialized pointer. receber是一个未初始化的指针。 scanf expects a char* where the read characters will be written down. scanf需要一个char* ,其中读取的字符将被写下来。 But in your case it points to some memory that you are not supposed to access.但在您的情况下,它指向一些您不应该访问的内存。 Trying to access it is undefined behavior.尝试访问它是未定义的行为。 In your case it results in segmentation fault.在您的情况下,它会导致分段错误。

Among many some solutions would be to use char receber[MAXLEN+1] or char * receber = malloc(MAXLEN+1) .在许多解决方案中,将使用char receber[MAXLEN+1]char * receber = malloc(MAXLEN+1) There is a case here now.现在这里有一个案例。 The first solution will result in an array which is of automatic storage duration - long story short, when the function ends it will point to some memory that will be invalid - so you can't return it (if you use first solution).第一个解决方案将产生一个自动存储持续时间的数组 - 长话短说,当函数结束时,它将指向一些无效的内存 -所以你不能返回它(如果你使用第一个解决方案)。

Second solution will allocate memory dynamically which will have storage duration beyond the scope of this function.第二种解决方案将动态分配内存,这将具有超出此功能范围的存储持续时间。 This will be the correct one to use in this case.这将是在这种情况下使用的正确方法。

For var in other function you can use dynamic memory allocation or VLA support if you have one.对于其他函数中的var ,您可以使用动态内存分配或 VLA 支持(如果有的话)。 You should allocate memory of size equal to the length of the string.您应该分配大小等于字符串长度的内存。 Here it doesnt stop at allocation - you need to initialize it with values so that you can use it in arithmetic operation like you did.在这里它不会在分配时停止 - 您需要用值初始化它,以便您可以像您一样在算术运算中使用它。 (Using it uninitialized again is undefined behavior) (再次使用它未初始化是未定义的行为)

For your information there is a function named strlen which gives you the length of a string (nul terminated char array) - use it here.为了您的信息,有一个名为strlen的函数,它为您提供字符串的长度(以 nul 结尾的字符数组) - 在此处使用它。

Also if you check the reference manual or man pages you will see pow returns double - so here in case you will face some precision issues.此外,如果您查看参考手册或手册页,您会看到pow返回双倍 - 所以在这里您会遇到一些精度问题。 For calculating integral power use custom functions - it is better in case of precision and avoiding nasty precision errors.对于计算积分功率使用自定义函数 - 在精度和避免令人讨厌的精度错误的情况下更好。

You are confusing pointers with arrays.您将指针与数组混淆了。 A pointer just points;一个指针只是指向; declaring a pointer does not reserve memory, it just creates a pointer variable pointing to some undefined place.声明一个指针不保留内存,它只是创建一个指向某个未定义位置的指针变量。

Corrected program:修正程序:

char *recepcao(char *receber) {
    scanf("%s", receber);
    return receber;
}
int conversao(char *string) { int i, j;
    for(i=0; string[i]!='\0'; ++i) {
        continue;
    }
    int var[100];
    int contagem=0;
    for(j=0; j<i-1; ++j) {
        var[j]=(string[j]-'0');
        contagem+=var[j]*pow(10, (i-j-1));
    }

    return contagem;
}
int main() {
    char receber[100];
    printf("%i", conversao(recepcao(receber))); return 0;
}

Update:更新:

Arrays and pointers are used in a very similar manner in C, but they are not the same.数组和指针在 C 中的使用方式非常相似,但它们并不相同。 When you declare an array, the compiler reserves the required memory:声明数组时,编译器会保留所需的内存:

int a[10], b[10];
a[1] = 1;  // OK
a = b;     // Error!

Element of array is variable, but array name is not .数组的元素是可变的,但数组名不是 Array name is sort of label, you cannot change its value so that it pointed to another array.数组名称是一种标签,您不能更改其值以使其指向另一个数组。

Pointer is variable.指针可变的。 When you declare a pointer, the compiler creates it with undefined contents (like any other variable).当您声明一个指针时,编译器会使用未定义的内容(与任何其他变量一样)创建它。

int *p, *q;
p = q;      // OK but useless because both the pointers contain junk addresses
a[0] = *p;  // Depending on where p points you will get either junk in a[0] or memory access violation
. . . 
p = a;                 // Now you can use p as a synonym for array a declared above
if (*(p + 1) == a[1])  // Always true
if (p[2] == *(a + 2))  // Always true
. . .
b = p;   // This won't work; can't assign a new value to array name b
. . .
q = (int*)malloc(sizeof(int) * 10); // Another way of creating int array of 10 elements
q = p;  // Array created with malloc is lost because nothing points to it now

Basically, the only difference between pointers and arrays is that pointer is variable and array name is not.基本上,指针和数组之间的唯一区别是指针是变量而数组名称不是。 You can't write "a = p" exactly as you can't write "2 = i".你不能像写“2 = i”一样写“a = p”。

There also is a rather confusing quirk with array as a formal argument:将数组作为正式参数还有一个相当令人困惑的怪癖:

   void xyz(int a[10]) {
       . . .
   }

   void main() {
       int b[20];
       . . .
       xyz(b);
   }

Looks like we assign b to a, and change array size, right?看起来我们将 b 分配给 a,并更改数组大小,对吗? No, "int a[10]" is treated as "int *a", and sizeof(a) will return the size of the pointer, not the size of the array.不,“int a[10]”被视为“int *a”,sizeof(a) 将返回指针的大小,而不是数组的大小。

Several problems here这里有几个问题

char *recepcao() { 
    char *receber;
    scanf("%s", receber);
    return receber;
}

has 2 errors: receber is an uninitialized pointer, it's pointing to nowhere in particular, so passing to scanf is an undefined behaviour.有 2 个错误: receber是一个未初始化的指针,它特别指向任何地方,因此传递给scanf是一种未定义的行为。

Also receber is a local variable of recepcao and it ceases to exists when recepcao returns, so you are returning a pointer to invalid memory location.此外receber是一个局部变量recepcao ,它不再存在时, recepcao的回报,所以你是返回一个指向无效的内存位置。

It would be better that you declare an array in main and pass that array (with its size) to the functions.最好在main声明一个数组并将该数组(及其大小)传递给函数。 I also would use fgets instead of scanf , it easier to control fgets .我也会使用fgets而不是scanf ,它更容易控制fgets

You can use strlen(string) instead of您可以使用strlen(string)而不是

for(i=0; string[i]!='\0'; ++i) {
        continue;
}

but that's ok if you are not allowed to use strlen in your assignment.但是如果你不允许在你的作业中使用strlen也没关系。

Also using pow is overkill here, there is no need to include floating point arithmetic ( pow returns a double ) when you could use a variable exp initialized to 1 and multiply it by 10 in every loop (see my code below).同样在这里使用pow是多余的,当您可以使用初始化为 1 的变量exp并在每个循环中将其乘以 10 时,无需包含浮点算术( pow返回double )(请参阅下面的代码)。

Also

int *var;
...
for(j=0; j<i-1; ++j) {
    var[j]=(string[j]-'0');
    ...

is not going to work because var is not initialized.不会工作,因为var未初始化。 There is no need to use a pointer here anyway, not even an array, you are not doing anything with the saved values.无论如何都不需要在这里使用指针,甚至不需要使用数组,您不会对保存的值做任何事情。 It would be better to use a single char variable:最好使用单个char变量:

char var;
...
for(j=0; j<i-1; ++j) {
    var = string[j] - '0';
    ...

So you can rewrite your program with this information like this:因此,您可以使用以下信息重写您的程序:

#include <ctype.h>

char *recepcao(char *receber, size_t len) {
    if(fgets(receber, len, stdin) == NULL)
    {
        fprintf(stderr, "Could not read from user\n");
        return NULL;
    }

    // removing newline
    receber[strcspn(receber, "\n")] = 0;

    return receber;
}

int conversao(const char *string) { 
    if(string == NULL)
        return 0;

    size_t len = strlen(string);

    int res = 0, pow = 1;

    for(size_t i = len - 1; i >= 0; --i)
    {
        if(isdigit(string[i]))
        {
            res += (string[i] - '0') * pow;
            pow *= 10;
        } else {
            fprintf(stderr, "'%s' contains non-digits\n", string);
            return 0;
        }
    }

    return res;
}

int main(void)
{
    char line[100];

    if(recepcao(line, sizeof line) == NULL)
        return 1;

    printf("%d\n", conversao(line));

    return 0;
}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM