Warning: file_get_contents(/data/phpspider/zhask/data//catemap/4/c/64.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181

Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/linux/23.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C 对导致分段错误的字符串文字使用strtol_C_Linux_Strtok_Strtol - Fatal编程技术网

C 对导致分段错误的字符串文字使用strtol

C 对导致分段错误的字符串文字使用strtol,c,linux,strtok,strtol,C,Linux,Strtok,Strtol,我有一个通过getline()获得的字符串(更准确地说,我使用循环和getline逐行读取文件) 假设行是12 | 34 | 然后我使用strtok()将其缩减为substr=strtok(行“|”) 并使用循环将它们存储到字符串数组中,part[index]=substr 所以这里的[0]部分应该是“12”,而[0]部分应该是“34” 我想使用strtol,但我已经检查过它不能用于字符串文字,然后我尝试下面的代码 char *temp = strdup(part[1]); char **ptr

我有一个通过
getline()
获得的字符串(更准确地说,我使用循环和
getline
逐行读取文件)

假设行是
12 | 34 |

然后我使用strtok()将其缩减为
substr=strtok(行“|”)
并使用循环将它们存储到字符串数组中,
part[index]=substr

所以这里的[0]部分应该是“12”,而[0]部分应该是“34” 我想使用strtol,但我已经检查过它不能用于字符串文字,然后我尝试下面的代码

char *temp = strdup(part[1]);
char **ptr;
long ret = strtol(temp, ptr, 10);
printf("%x\n", ret);

当我读第二行时,它会导致分段错误。通过如何真正使用
strtol
将字符串转换为整数

问题在于
ptr
没有初始化。因此,当strtol试图在地址ptr写入时,它会崩溃(或出现未定义的行为)

必须传递指针的有效地址才能存储最后一个未处理的字符,如:

char *ptr;
long ret = strtol(temp, &ptr, 10);

&ptr
有效,并指向自动变量存储位置,指向
ptr
您误用的
strtol
。它需要一个
char**
,因为它打算根据手册页设置它指向的
char*

如果
endptr
不是
NULL
strtol()
将第一个无效字符的地址存储在
*endptr

通过将未初始化的
char**
传递给它,当它试图取消引用它时,将调用未定义的行为。将代码更改为:

char *ptr;  // Place to put the end ptr
long ret = strtol(temp, &ptr, 10);  // Pass address of the location it can set
或者,如果您从未使用过
ptr
,只需执行以下操作:

long ret = strtol(temp, NULL, 10);  // Don't care about end ptr; strtol won't set on NULL

这里你已经把你的绳子分开了。 所以每个字符串包含一个长数字。第二个参数用于知道转换在字符串中的何处停止。 如果您不需要它,请传入
NULL

char *temp = strdup(part[1]);
long ret = strtol(temp, NULL, 10);
printf("%lx\n", ret);
此外,
printf
对于长数字,需要不同的格式标志。这里是长十六进制的
lx

char **ptr;
long ret = strtol(temp, ptr, 10);
这是错误的
ptr
未初始化,未引用任何有用的内容

strtol()
的第二个参数必须引用存储第一个未转换字符地址的实际
char*
值的地址。Per:

指向最后一个字符串的指针存储在 endptr,前提是endptr不是空指针

正确的代码应该是

char *endptr;
long ret = strtol(temp, &endptr, 10);

在这种情况下,调用
strtol()
后,
endptr
中的值将是未转换为结果
long
值的第一个字符的地址

如果您不关心第一个未转换的字符是什么:

char **ptr;
long ret = strtol(temp, NULL, 10);
函数
strtol(const char*str,char**str\u end,int base)
将取消引用
str_end
,并将执行类似于
*str_end=u解析后的一个_long
;因此,当您传递类型为
char**
的指针时,该指针不指向可由
strtol
修改的有效指针对象,则会产生未定义的行为

你宁愿写信

char *ptr;  // space for taking on a pointer value
long ret = strtol(temp, &ptr, 10);
或(不是首选变体):


完全不需要使用
strtok()
,因为
strtol()
将第二个参数所指向的指针设置为指向解析数字后面的字符

完整的示例程序:

#define  _POSIX_C_SOURCE  200809L
#include <stdlib.h>
#include <stdio.h>
#include <errno.h>

int main(void)
{
    char    *line_ptr = NULL;
    size_t   line_max = 0;
    ssize_t  line_len;

    long    *number      = NULL;
    size_t   numbers     = 0;
    size_t   numbers_max = 0;

    char    *curr, *next, *ends;
    long     temp;
    size_t   i;

    while (1) {

        line_len = getline(&line_ptr, &line_max, stdin);
        if (line_len < 1)
            break;

        curr = line_ptr;
        ends = line_ptr + line_len;

        numbers = 0;
        while (1) {

            /* Parse next long. */
            next = curr;
            errno = 0;
            temp = strtol(curr, &next, 0);
            if (errno)
                break;
            if (next == curr)
                break;

            /* Need to grow number array first? */
            if (numbers >= numbers_max) {
                size_t  temp_max = (numbers | 1023) + 1025 - 16;
                long   *temp_ptr;

                temp_ptr = realloc(number, temp_max * sizeof number[0]);
                if (!temp_ptr) {
                    fprintf(stderr, "Out of memory.\n");
                    exit(EXIT_FAILURE);
                }

                numbers_max = temp_max;
                number      = temp_ptr;
            }

            /* Save parsed number. */
            number[numbers++] = temp;

            /* Skip trailing whitespace, */
            curr = next;
            while (curr < ends && (*curr == '\t' || *curr == '\n' || *curr == '\v' ||
                                   *curr == '\f' || *curr == '\r' || *curr == ' '))
                curr++;

            /* Skip separator. */
            if (*curr == '|')
                curr++;
            else
                break; /* No separator, so that was the final number. */
        }

        printf("Parsed %zu longs:", numbers);
        for (i = 0; i < numbers; i++)
            printf(" %ld", number[i]);
        printf("\n");
        fflush(stdout);
    }

    if (ferror(in)) {
        fprintf(stderr, "Error reading standard input.\n");
        exit(EXIT_FAILURE);
    }

    free(line_ptr);
    line_ptr = NULL;
    line_max = 0;

    free(number);
    number = NULL;
    numbers = 0;
    numbers_max = 0;

    return EXIT_SUCCESS;
}

取决于这样一个事实,即如果要转换的数字的大小太大,
strtol()
将设置
errno=ERANGE
,并返回
LONG\u MIN
(如果字符串中的数字为负数)或
LONG\u MAX
(如果为正数)。要检测到这一点,我们必须先将
errno
设置为零。如果字符串为空(或者行中有一个零散的nul字符,
\0
strtol()
将返回0,并带有
next==curr

旁注:您从未对字符串文本调用过
strtol
,因此我不确定您的标题来自何处。您最初认为不能对字符串文本调用
strtol
,这是错误的。虽然所有关于ptr和strtol的错误用法的观察都是正确的,但我怀疑这会导致分段错误。你能发布一个更完整的代码版本吗?特别是第[]部分的定义?@Germanner如果你将一个非空指针传递给
strtol
,它将尝试在这个地址写入,所以是的,它很可能会发生segfult(如果你的系统有一个MMU)@Jean-François Fabre OP的代码声明了一个指向char*的指针。未初始化时,它在堆栈上分配,如果编译器接受从指针到char*到char*的隐式转换(如gcc所做的),strtol()可以写入它。只有在取消对未初始化指针的引用时,才能创建segfault。是的,分配了
**ptr
指针,但
strtol
取消对它的引用(读取它的值)以在那里写入内容(它是指针上的指针)。所以这是未定义的行为。
ptr
的值对于指针无效。当然,
&ptr
是初始化的,但这不是重点。*第二个参数不限制转换的大小,它报告转换的结束位置。差别很大。是的,我显然不知道如何解读一个男人。我的坏消息,更新了。
char **ptr = malloc(sizeof(char*));
long ret = strtol(temp, ptr, 10);
...
free(*ptr);
#define  _POSIX_C_SOURCE  200809L
#include <stdlib.h>
#include <stdio.h>
#include <errno.h>

int main(void)
{
    char    *line_ptr = NULL;
    size_t   line_max = 0;
    ssize_t  line_len;

    long    *number      = NULL;
    size_t   numbers     = 0;
    size_t   numbers_max = 0;

    char    *curr, *next, *ends;
    long     temp;
    size_t   i;

    while (1) {

        line_len = getline(&line_ptr, &line_max, stdin);
        if (line_len < 1)
            break;

        curr = line_ptr;
        ends = line_ptr + line_len;

        numbers = 0;
        while (1) {

            /* Parse next long. */
            next = curr;
            errno = 0;
            temp = strtol(curr, &next, 0);
            if (errno)
                break;
            if (next == curr)
                break;

            /* Need to grow number array first? */
            if (numbers >= numbers_max) {
                size_t  temp_max = (numbers | 1023) + 1025 - 16;
                long   *temp_ptr;

                temp_ptr = realloc(number, temp_max * sizeof number[0]);
                if (!temp_ptr) {
                    fprintf(stderr, "Out of memory.\n");
                    exit(EXIT_FAILURE);
                }

                numbers_max = temp_max;
                number      = temp_ptr;
            }

            /* Save parsed number. */
            number[numbers++] = temp;

            /* Skip trailing whitespace, */
            curr = next;
            while (curr < ends && (*curr == '\t' || *curr == '\n' || *curr == '\v' ||
                                   *curr == '\f' || *curr == '\r' || *curr == ' '))
                curr++;

            /* Skip separator. */
            if (*curr == '|')
                curr++;
            else
                break; /* No separator, so that was the final number. */
        }

        printf("Parsed %zu longs:", numbers);
        for (i = 0; i < numbers; i++)
            printf(" %ld", number[i]);
        printf("\n");
        fflush(stdout);
    }

    if (ferror(in)) {
        fprintf(stderr, "Error reading standard input.\n");
        exit(EXIT_FAILURE);
    }

    free(line_ptr);
    line_ptr = NULL;
    line_max = 0;

    free(number);
    number = NULL;
    numbers = 0;
    numbers_max = 0;

    return EXIT_SUCCESS;
}
next = curr;
errno = 0;
temp = strtol(curr, &next, 0);
if (errno)
    break; /* errno == ERANGE; number too large in magnitude! */
if (next == curr)
    break; /* end of input, no number */