【问题标题】:C's printf doesn't print a string (char array) outC 的 printf 不打印字符串(字符数组)
【发布时间】:2011-07-18 17:48:18
【问题描述】:

我的问题基本上是使用 printf 打印一个字符数组。

在某些情况下,它会打印出结果:

int main(int argc, char** argv) {
  char* orig = "@reveals#?the treasure chest#$President Barack H. Obama#";
  printf("The input: %s\n", orig);
  printf("The output: %s\n", reArrange(orig));

  return (EXIT_SUCCESS);
}

有时不会:

int main(int argc, char** argv) {
  char* orig = "@reveals#?the treasure chest#$President Barack H. Obama#";
  printf("%s\n", reArrange(orig));

  return (EXIT_SUCCESS);
}

下面是完整代码(包含main函数):

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

#define SUBJECT '$'
#define ACTION '@'
#define OBJECT '?'
#define END '#'

char* reArrange(char* orig) {
  int origSize = strlen(orig);

  char subject[origSize], action[origSize], object[origSize];

//int i;
//for(i = 0; i < origSize; i++) {
//  subject[i] = ' ';
//  action[i] = ' ';
//  object[i] = ' ';
//}
  int subjectIndex = 0,   actionIndex = 0,  objectIndex = 0;

  int timesEndCharShowUp = 0;

  char state;
  int i;
  for(i = 0; i < origSize; i++) {
    char ch = orig[i];

    if(ch == SUBJECT) {
      state = SUBJECT;
    }
    else if(ch == ACTION) {
      state = ACTION;
    }
    else if(ch == OBJECT) {
      state = OBJECT;
    }
    else if(ch == END) {
      if(timesEndCharShowUp == 3) {
        break;
      }
      else {
        timesEndCharShowUp++;
      }
    }
    else {
      if(state == SUBJECT) {
        subject[subjectIndex++] = ch;
      }
      else if(state == ACTION) {
        action[actionIndex++] = ch;
      }
      else if(state == OBJECT) {
        object[objectIndex++] = ch;
      }
    }
  }

  subject[subjectIndex] = '\0';
  action[actionIndex] = '\0';
  object[objectIndex] = '\0';

  char rearranged[origSize];
  sprintf(rearranged, "%s %s %s.\0", subject, action, object);
  //printf("%s\n", rearranged);

  orig = rearranged;
  return orig;
}

int main(int argc, char** argv) {
  char* orig = "@reveals#?the treasure chest#$President Barack H. Obama#";
//  printf("The input: %s\n", orig);
//  printf("The output: %s\n", reArrange(orig));
  printf("result: ");
  printf("%s\n", reArrange(orig) );
//fflush(stdout);

  return (EXIT_SUCCESS);
}

【问题讨论】:

    标签: c string printf


    【解决方案1】:

    您正在返回一个指向驻留在堆栈上的内存的指针。 rearranged 在封闭函数 (reArrange) 返回后不可用,并且可能包含垃圾。

    您可能想要malloc rearranged 或全局声明它。

    【讨论】:

    • @Clifford: static 确实意味着全局但仅在封闭函数中可见。
    • 我明白了,但为什么printf("The input: %s\n", orig);printf("The output: %s\n", reArrange(orig));works?
    • 当它起作用时,你很幸运。了解堆栈的工作原理以及未定义的行为。
    • @Blagovest:一点也不!全局变量隐含static,反之则不成立。 static 分配与变量的生命周期有关,另一方面,全局性与可见性和范围有关-如果它具有本地范围,则根据定义全局。当然,当您返回一个非const 指向它的指针时,通过使其成为本地获得的任何保护都将在很大程度上丢失。无论如何,Rudy 的解决方案是更好、更常用的解决方案。
    • 我不敢相信 6 票建议使用全局! Required reading;忘记它指的是嵌入式系统;原则适用,错误... 全局 ;)
    【解决方案2】:

    不是只返回一个char *,而是让reArrange() 接受一个可以写入结果的缓冲区。现在调用者必须为您的函数提供合适的缓冲区,并且您不再有内存管理问题。您只需将 strncpy() 安排到缓冲区。为了确保缓冲区足够大,用户还应该在第三个参数中提供缓冲区的大小:

    char *rArrange(char *orig, char *result, int resultSize)
    {
        if (!result || resultSize == 0)
            return NULL;
    
        /* your code here */
    
        strncpy(result, arranged, resultSize);
        return result;
    }
    

    存储结果的替代malloc() 对用户来说不是很友好(用户必须 freemem() 缓冲区,但可能不知道这一点)。使用静态/全局缓冲区不是线程安全的。

    【讨论】:

      【解决方案3】:

      你的函数需要两个参数:

      char* reArrange(char* orig)
      

      应该是:

      char* reArrange(char *rearragned, char* orig) {
      
      // make your magic here!
      
      }
      

      调用顺序:

      char input[SIZE];
      char rearrange [SIZE];
      
      // initialize everything! Don't forget to rearrange[0] ='\0\;!!!
      
      rearrange(rearranged, input);
      
      // do you printing....
      

      您还应该学习如何正确使用指针并查找“开关”。

      【讨论】:

      • rearrange[0] 在这种情况下不需要初始化,尽管您可以选择这样做。
      【解决方案4】:

      问题是您的函数reArrange 返回一个指向它不再控制的内存的指针。返回rearranged 数组的地址。在返回发生后,这个数组实际上不再存在——内存可以并且将会被重用。

      修复错误的快速技巧是将rearranged 声明为static。长期的解决方法是学习 C 的工作原理并使用 malloc() 或等效的代码编写一些东西。

      【讨论】:

      • 实际上在某些情况下将其声明为静态既足够又安全;不一定是hack。如果你在reArrange() 内动态分配它,你就是让调用者负责处理它,所以调用者必须知道它是如何分配的。 @Rudy Velthuis 详细介绍了一个更好(也是最传统)的解决方案,然后调用者决定分配和处置,这可能是动态的,也可能不是动态的。 static 声明将使函数不可重入,因此不是线程安全的——正如我所说的“在某些情况下......”。
      • @Clifford --“实际上”,将其声明为静态会使函数非线程安全。因此,这是一个 hack——尤其是当推荐给一个不知道发生了什么的 OP 时。
      • 是的,它使它成为非线程安全的;这正是我所说的,没有争论 - 我确实“在某些情况下”强调了两次。在许多情况下,线程安全不是问题。例如当应用程序不是多线程的,或者该函数只能在单线程中使用时。您的建议在单线程和多线程应用程序中都存在内存泄漏的可能性。正如我所说,最好的解决方案不是这些,但我会在返回动态分配的块之前放置静态分配。
      【解决方案5】:

      使用char rearranged[origSize];,您创建了一个新的字符数组,一旦reArrange 终止,它就会超出范围。所以在reArrange 的生命周期中,rearranged 是一个指向有意义的东西的指针;因此,orig = rearranged 是有意义的。

      但一旦超出范围,reArrange(orig) 将返回指向 rearranged 的指针,这是一个悬空指针,现在 rearranged 不再存在。

      【讨论】:

        【解决方案6】:

        您确定以下代码部分有效吗?

        char* reArrange(char* orig) {
          int origSize = strlen(orig);
        
          char subject[origSize], action[origSize], object[origSize];
        

        我的意思是 origSize 必须是 const 它不能是动态值。您应该使用mallocsubject , action and object 分配空间。 此外,您可以考虑一些准则:

        1 代替:

        for(i = 0; i < origSize; i++) {
            char ch = orig[i];    
            if(ch == SUBJECT) {
              state = SUBJECT;
        }
        

        你可以拥有:

        char ch;//declare char ch outside for loop
        for(i = 0; i < origSize; i++) {
            ch = orig[i];
        
            if(ch == SUBJECT) {
              state = SUBJECT;
            }
        

        2 您可能希望使用switch 语句而不是if,这将使您的代码看起来很棒。

        【讨论】:

        • 是的,该部分有效。去年夏天学了C,一年多用Java的时候很快就忘记了大部分不直观的东西……真的,switch更好~~
        • 我对第一个指南感兴趣,它背后的原因是什么?
        猜你喜欢
        • 1970-01-01
        • 2016-02-11
        • 2018-02-17
        • 2021-01-30
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2012-07-26
        相关资源
        最近更新 更多