为什么第二个参数不适用于 strtol?

Why is the second argument not working with strtol?

我是这样做的:

/* convert the argv[1] into Integer and store the result in key
 * using library function: strtol() to do it */
char **flag = NULL;
key = strtol(argv[1], flag, 10);

// if argv[1] is not all digits
if (**flag != '[=10=]')
{
    printf("Usage: ./caesar key\n");
    return 1;
}

但是它抛出一个分段错误。我不知道为什么。

在 C 文档中,strtol 的原型为 long int strtol(const char *nptr, char **endptr, int base)。为什么我会出现分段错误?

并且当将代码的某些部分更改为 char *flagstrtol(argv[1], &flag, 10)if (*flag != '[=15=]') 时,一切都按预期工作。

我了解(某种程度上)进行编辑如何更正代码。但是,我不知道为什么原始代码不起作用。有人知道吗?

您需要传递您的 char * 指针的地址,以便 strtol 可以更新它。

char *flag = NULL;
key = strtol(argv[1], &flag, 10);

// if argv[1] is not all digits
if (*flag != '[=10=]')

调用后,指针将被修改为指向输入字符串解析区域的末尾。

手册页的措辞确实令人困惑。

I do not know why the original code does not work? Does anyone have any clue?

因为这里

char **flag = NULL;

flag设为NULL,那么这里

key = strtol(argv[1], flag, 10);

flags的值(NULL)传递给strtol(),这不会以任何方式改变flags的值,它是NULL 在调用 strtol().

之前和之后

终于到了

if (**flag != '[=12=]')

flag,其值为 NULL,被取消引用,这会调用未定义的行为,这可能导致任何事情,在您的情况下是崩溃。

考虑这个将数字乘以 2 的简单函数。

void Times2(int number, int *result)
{
  *result = number * 2;
}

你应该这样称呼它:

int result;
Times2(3, &result);
printf("%d\n", result);

预期输出为 4

但是如果你这样调用它(这基本上就是你在错误代码中调用 strtol 时所做的):

int *result = NULL;
Times2(3, result);
printf("%d\n", result);

你的程序很可能会以段错误结束,因为在 Times2 函数中你取消引用了一个 NULL 指针。

Why second argument not working with strol?

char **flag = NULL;
key = strtol(argv[1], flag, 10);

正在运行。传递 空指针 没问题,但 flag 不会在调用代码中更改。

当第二个参数是一个空指针时,没有关于转换结束位置的更新。


后面的代码:if (**flag != '[=16=]') 中的 *flag 是错误的(未定义的行为),因为它试图取消引用空指针。


改为传递已知指针的地址:

//char **flag = NULL;
char *flag;

//key = strtol(argv[1], flag, 10);
key = strtol(argv[1], &flag, 10);

// if (**flag != '[=11=]')
if (*flag != '[=11=]') 

以下是 char*int 的完整测试转换。

#include <stdlib.h>
#incluse <ctype.h>

// Return error flag
int my_strtol(long *destination, const char *s) {
  if (destination == NULL) {
    return 1;
  } 
  if (s == NULL) {
    *destination = 0;
    return 1;
  }

  char *endptr;
  errno = 0;
  *destination = strtol(s, &endptr, 0); 

  // If no conversion or out-of-range
  if (s == endptr || errno == ERANGE) {
    return 1;
  }
  // I like to tolerate trailing white-space.
  while (isspace(*(const unsigned char *) endptr)) {
    endptr++;
  }
  return *endptr != '[=12=]';
}