【问题标题】:C - place integer in a char array and extract itC - 将整数放在 char 数组中并提取它
【发布时间】:2016-10-07 23:17:05
【问题描述】:

C 中的字符串操作是我存在的祸根,我试图了解如何操作 char 数组并且每次都无法掌握它。我只是想在 C 中做到这一点。

Method1 passes ["1298","9"]
Method2 receives and converts them both to ints

int method1(){
  char *values[2];
  int i = 1298;
  int j = 9;

  //sprintf(values,"%d" "%d",i,j);
  sprintf(&values[0],"%d" ,i);
  sprintf(&values[1],"%d" ,j);
  method2(values,2);
}
int method2(char *strings, int num_values){
   int i, j;
   char buffer[256];
   sscanf(buffer, "%d" "%d", &i, &j);
   printf("i: %d, j: %d\n",i,j);
   return 0;
}

这样的结果是1和9;但我想要 1298 和 9 请即使在提供答案后,您能解释一下为什么会这样吗?

【问题讨论】:

    标签: c arrays string char scanf


    【解决方案1】:

    程序的结果称为UNDEFINED BEHAVIOR。如果您正在学习,则必须使用编译器警告。

    您的代码有很多问题,您应该阅读 中的字符串,而不是仅仅为了看看它们是否有效而尝试。

    1. 你使用了sprintf()错误,你应该传递一个指向char的指针作为第一个参数,它指向有效数据。您正在传递未初始化的指针,这会导致 未定义的行为

    2. 函数method1()请注意,方法用于类或对象,在 中没有方法,只有函数)也没有在任何地方传递任何东西。指针数组values 是函数本地的,不能从函数外部访问。要将某些东西传递 给一个函数,你应该通过参数来代替它,因为你不能从 程序调用main(),因为它是未定义的行为。

    3. 您使用的是sscanf(),而您显然是fscanf() 或只是scanf()

      如果您想读取用户的输入,请使用

      if (scanf("%d %d", &i, &j) == 2)
          printf("i: %d, j: %d\n", i, j);
      else
          printf("Invalid input\n");
      

      您可以将scanf() 替换为fscanf(stdin, ... 或另一个FILE * 对象以从文件中读取。

      在您的代码中,您的程序期望buffer 包含一个字符串('\0' 结尾的字节序列)。您正在传递一个未初始化的数组,而不是调用 未定义的行为

      如果您想测试sscanf() 的工作原理,请执行此操作

      char buffer[] = "1 2";
      if (sscanf(buffer, "%d %d", &i, &j) ...
      

      其他的都一样。

    我会说,你想要这个

    int
    main(void)
    {
        char buffer[256];
        int i;
        int j;
    
        sprintf(buffer, "%d %d", 1289, 9); // - This is not necessay, but for illustration
                                           // - This is also, unsafe as it could cause
                                           //   a buffer overflow.
        if (sscanf(buffer, "%d %d", &i, &j) == 2) // Would be surprised if this is false,
            printf("values: %d %d\n", i, j);      // but you MUST always check to make 
        else                                      // sure, because this kind of situation
            printf("invalid input?\n");           // is very unusual in real code.
    
    }
    

    我希望您能明白,为什么您的代码如此错误。您也可以将您想要的部分移动到该功能。但它应该是正确的部分。

    【讨论】:

    • 但在这种情况下我没有得到用户输入,我有值,我如何将它们放入数组中以通过接收方法正确提取它们?
    • @i_use_the_internet 你的代码太错误了,所以你应该删除它,阅读c编程并重新开始。
    【解决方案2】:

    试试这个:

    char values[10]; int i = 1298; int j = 9; sprintf(values,"%d %d",i,j);

    【讨论】:

      【解决方案3】:

      这是我快速写下的内容;你可以将一个字符串数组连同它的长度一起传递给这个函数,它会动态分配一个整数数组及其转换后的值。

      这里的陷阱是strtol:如果它无法转换其中一个字符串,它将默认为 0。因此,如果字符串数组中的一个元素恰好包含一些非数字字符,你可能不会得到什么你期待;并且不会报告错误,因为您还必须确认字符串本身不是 0。

      #include <stdlib.h>
      #include <stdio.h>
      
      int *convert_to_int_array(const char **strings, size_t length) {
          int *numbers = malloc(length * sizeof(int));
          size_t i = 0;
      
          if(numbers == NULL)
              return NULL;
      
          for(i = 0; i < length; i++) {
              numbers[i] = strtol(strings[i], NULL, 10);
          }
          return numbers;
      }
      
      int main(int argc, char **argv) {
          const char *strings[2];
          strings[0] = "100";
          strings[1] = "50";
          int *numbers;
          size_t length = 2, i;
      
          numbers = convert_to_int_array(strings, length);
          if(numbers == NULL) {
              fprintf(stderr, "failed to initialize numbers\n");
          }
      
          for(i = 0; i < length; i++) {
              printf("%d\n", numbers[i]);
          }
          return EXIT_SUCCESS;
      }
      

      【讨论】:

      • 我使用fprintf 来展示一种处理错误的方式;人们通常不喜欢忽略错误的答案。至于我的编码风格,它与问题并不真正相关。
      • 我不认为这很糟糕。程序员永远不应该忽略错误。但是您的答案对于OP的级别来说太高级了。你应该把自己放在他的处境中,注意他甚至不知道如何使用sprintf()。如果是这样,你的回答对他有什么帮助?您的编码风格与我相关,而不是与问题相关。
      • 现在,情况更糟了。为什么你认为strtol() 有第二个参数?
      • @iharob 根据strtol 的手册页;第二个参数可以是 NULL,只要它是 NULL 终止的;这恰好是 C 字符串的情况。并且 OP 的示例不包含具有许多整数的字符串;那将是一个不同的答案。
      • 不,你错了。你是说有一个陷阱,你可以用第二个参数来解决它。它提供了一个指向 未转换 字符的指针。仔细阅读手册页。你认为因为它可以是NULL 它应该是NULL.?
      【解决方案4】:
          char *values[2];
      

      上面的行被解析为char *(values[2]);,即[]优先于*。这意味着 values 是一个包含 2 个元素的数组。元素的类型是char *。所以,values[0]values[1] 的类型是 char *。由于您尚未初始化数组元素,因此数组中的两项具有未知的随机值。

          //sprintf(values,"%d" "%d",i,j);
      

      尽管您已对此进行了注释,但您似乎正在尝试使用一个 sprintf 调用将 ij 的字符串表示形式存储到 values 中。您可能已经发现,这是不可能的。

          sprintf(&values[0],"%d" ,i);
      

      在这里,您调用sprintfi 的字符串表示形式存储到values[0] 指向的内存位置。但如上所述,values[0] 没有指向任何有用的地方,因为您还没有初始化它。这很糟糕。

          sprintf(&values[1],"%d" ,j);
      

      同上。

          method2(values, 2);
      

      在这里,您正在调用method2,但您尚未声明method2 的签名。事实证明,method2 需要一个 char * 和一个 int。您正在传递values2valueschar * 的数组,在此上下文中它被转换为指针,因此 method2 应该采用 char **int

      int method2(char *strings, int num_values){
      

      这应该是:int method2(char **strings, int num_values) {

          int i, j;
          char buffer[256];
          sscanf(buffer, "%d" "%d", &i, &j);
      

      我不确定您要在这里做什么。您忽略了strings,而是使用buffer 变量。 buffer 未初始化,因此试图将其中的数据解释为两个整数是没有意义的。

      我假设您编写这个程序是为了理解字符串、指针和函数。因此,没有一种正确的方法可以做你想做的事情。但这里有一种方法:

      #include <stdio.h>
      /* Define method2 before method1, so that its definition is visible
         in method1 */
      
      /* Assume that method2 will be called with one char * containing two integer
         values.  I also changed the return type to void since you weren't really
         using the int return value.  Same for method1. */
      void method2(const char *strings)
      {
          int i, j;
          sscanf(strings, "%d %d", &i, &j);
          printf("i: %d, j: %d\n",i,j);
      }
      
      void method1(void)
      {
          /* Changed values to a char array that has enough space */
          char values[256];
          int i = 1298;
          int j = 9;
      
          sprintf(values, "%d %d", i, j);
          method2(values);
      }
      
      int main(void)
      {
          method1();
          return 0;
      }
      

      以上输出:

      i: 1298, j: 9
      

      您的程序中有很多活动部分。我建议您在将指针、数组等用 C 语言传递给函数之前,先学习它们的基础知识。

      【讨论】:

        猜你喜欢
        • 2012-04-13
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2011-12-05
        • 2019-06-12
        相关资源
        最近更新 更多