简体   繁体   English

如何将一个字符指针数组从函数返回到main?

[英]How to return an array of character pointers from a function back to main?

I'm trying to store a list of files with a .txt extension into an array from my current working directory.我正在尝试将具有 .txt 扩展名的文件列表存储到我当前工作目录中的数组中。 I've gotten as far as getting the array together, now I just need to return it.我已经把数组放在一起了,现在我只需要返回它。 I'm new to C and I'm not used to the pointer situation.我是 C 新手,不习惯指针情况。 How can I return an array of char pointers?如何返回一个字符指针数组? I have the array created, and its allocated based on how many Text files I find in the directory.我创建了数组,并根据我在目录中找到的文本文件数量进行分配。

I'm getting two errors when I try to compile which leads me to believe that my understanding of pointers is not what I thought it was.当我尝试编译时遇到两个错误,这让我相信我对指针的理解与我想象的不同。 I also have been reading that my array will be destroyed when returning from the function, because it is on the stack.我也一直读到我的数组在从函数返回时会被销毁,因为它在堆栈上。 I'm not sure how to fix that.我不知道如何解决这个问题。 Any help or criticism would be welcome.欢迎任何帮助或批评。

    // prototypes
    char* getLine();
    void replaceWord();
    char * getTxtFilesInDir(char*);
    bool isTxt(char *);

    int main(int argc, char **argv) {

       // Check to see if correct number of arguments is given
       if (argc < 4) {
          printf("ERROR: Not enough parameters supplied. Please supply a find,"
                "replace, and prefix parameter and try again.\n");
          return -1;
       }

       // Initialize variables
       char *find, *replace, *prefix;
       find=argv[1];
       replace=argv[2];
       prefix=argv[3];
       char cd[1024];

       // Get the Current working directory to grab files
       if (getcwd(cd, sizeof(cd)) != NULL) {
          printf("Current working dir is: %s\n", cd);
       } else {
          perror("getcwd() error");
       }

       // Get the values of the arguments
       printf("Value of find: %s\nValue of replace: %s\nValue of prefix: %s\n",
             find, replace, prefix);

       // create an array of the files that are valid
       char* files = getTxtFilesInDir(cd);

       return 0;

    }
char*  getTxtFilesInDir(char* directory) {
   DIR *d;
   struct dirent *dir;
   d = opendir(directory);
   int n=0, i=0;

   // get the number of text files in the directory
   if (d) {
      while((dir = readdir(d)) != NULL) {
         if (isTxt(dir->d_name)) {
            n++;
         }
      }
   }

   rewinddir(d);
   // Create the array of text files depending on the size
   static char* txtFiles[n];

   // add the text files to the array
   if (d) {
      printf("Found: \n");
      while ((dir = readdir(d)) != NULL)
      {
         if (isTxt(dir->d_name)) {
            printf("%s\n", dir->d_name);
            txtFiles[i]= (char*) malloc (strlen(dir->d_name)+1);
            strncpy(txtFiles[i], dir->d_name, strlen(dir->d_name));
            i++;

         }
      }
      closedir(d);
   }
   return txtFiles;
}

bool isTxt(char *file) {
   size_t len = strlen(file);
   return len > 4 && strcmp(file + len -4, ".txt") == 0;
}

If you want that getTxtFilesInDir returns an array of strings, it should return a char** , not a char* .如果您希望getTxtFilesInDir返回一个字符串数组,它应该返回一个char** ,而不是一个char*

Also you don't need to declare the variable as static .此外,您不需要将变量声明为static You declare a variable in a function as static , when you want that the variable remains the same for all calls of the function.当您希望该变量对于函数的所有调用保持相同时,您可以将函数中的变量声明为static In this case this is probably not what you want to do.在这种情况下,这可能不是您想要做的。

Without modifying too much of your initial code, you can first allocate memory for an arrray of strings, and then resize it when you've got a new entry.无需修改太多初始代码,您可以先为一组字符串分配内存,然后在有新条目时调整其大小。 In this example I do that at once, because realloc(NULL, somesize) is the same as doing malloc(somesize) .在本例中,我立即执行此操作,因为realloc(NULL, somesize)与执行malloc(somesize) That's why it's important to initialize *tmp = 0 and txtFiles = NULL , so this trick works.这就是为什么初始化*tmp = 0txtFiles = NULL很重要,所以这个技巧有效。 You should also pass a pointer to an size_t where you store the number of entries:您还应该传递一个指向size_t的指针,您可以在其中存储条目数:

char **getTxtFilesInDir(const char* directory, size_t *len) {
    if(directory == NULL || len == NULL)
        return NULL;

    ...

    *len = 0;
    char **txtFiles = NULL, **tmp;
    char *str;

    if (d) {
      printf("Found: \n");
      while ((dir = readdir(d)) != NULL)
      {
         if (isTxt(dir->d_name))
         {
             tmp = realloc(txtFiles, (len+1) * sizeof *textFiles);
             if(tmp == NULL)
                 return txtFiles; // return what you've got so far


             str = malloc(strlen(dir->d_name) + 1);
             if(str == NULL)
             {
                 if(txtFiles == NULL) // first time, free everything
                 {
                     free(tmp);
                     return NULL;
                 }

                 return tmp; // return all you've got so far
             }

             strcpy(str, dir->d_name); // no need of strcnpy, you've allocated
                                       // enough memory
             txtFiles = tmp;
             txtFiles[(*len)++] = tmp;
         }
      }
      closedir(d);

      return txtFiles;
}

The important bits here is 1. how you expand the memory with realloc .这里的重要部分是 1. 如何使用realloc扩展内存。 Then it allocates memory for the string using malloc .然后它使用malloc为字符串分配内存。 I do that before txtFiles = tmp;我在txtFiles = tmp;之前这样做了, so that I don't have to write to many if(...==NULL) . ,这样我就不必写很多if(...==NULL) If something goes wrong along the way, the function returns all the file names it already has stored.如果在此过程中出现问题,该函数将返回它已经存储的所有文件名。

Now in main you do:现在main你做:

int main(int argc, char **argv)
{
    ...

    size_t len = 0;
    char **files = getTxtFilesInDir(cd, &len);

    if(file == NULL)
    {
        fprintf(stderr, "No files found\n");
        return 1;
    }

    for(size_t i = 0; i < len; ++i)
        printf("file: %s\n", files[i]);

    // freeing memory
    for(size_t i = 0; i < len; ++i)
        free(files[i]);

    free(files);

    return 0;
}

I also want to comment on your orginal way of copying:我还想评论一下您的原始复制方式:

strncpy(txtFiles[i], dir->d_name, strlen(dir->d_name));

strncpy is great when you want to limit the number of bytes to be copied.当您想限制要复制的字节数时, strncpy非常strncpy In your case you've already allocated enough memory, so there is no need to.在您的情况下,您已经分配了足够的内存,因此无需分配。 And when you use strncpy , the limit should be bound to the number of bytes available to the destination, not the source, otherwise you might copy more bytes than it should.并且当您使用strncpy ,限制应绑定到目标可用的字节数,而不是源可用的字节数,否则您复制的字节数可能会多于应有的字节数。 In your case you won't get a valid c-string, because you are limiting to copy to the lenth of dir->d_name , so the '\\0' -terminating won't be copied.在您的情况下,您将无法获得有效的 c 字符串,因为您只能复制到dir->d_name的长度,因此不会复制'\\0'终止。

man strcpy男人

#include <string.h> char *strcpy(char *dest, const char *src); char *strncpy(char *dest, const char *src, size_t n);

[...] [...]

The strncpy() function is similar, except that at most n bytes of src are copied. strncpy()函数类似,除了最多复制src n个字节。 Warning: If there is no null byte among the first n bytes of src , the string placed in dest will not be null-terminated.警告:如果src的前n个字节中没有空字节,则放置在 dest 中的字符串不会以空值结尾。

When you use strncpy you must make sure that the copy is a valid string by setting the '\\0' -terminating byte yourself.当您使用strncpy必须通过自己设置'\\0'终止字节来确保副本是有效的字符串。 Because you've allocated strlen(dir->d_name)+1 bytes for the string:因为您已经为字符串分配了strlen(dir->d_name)+1个字节:

strncpy(txtFiles[i], dir->d_name, strlen(dir->d_name));
textFiles[i][strlen(dir->d_name)] = 0;

Also the exit value of a program is a unsigned value, it goes from 0 to 255. In main you should return 1 instead of -1 on error.此外,程序的退出值是一个unsigned值,它从 0 到 255。在main您应该在出错时返回1而不是-1

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

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