在C上返回一个字符串

时间:2014-10-20 20:24:11

标签: c string segmentation-fault return

我得到核心转储,我不知道如何解决。我搜索了其他问题并搜索了我的问题,但我无法弄清楚如何解决这个问题...

以下是代码:

const char checkExtension(const char *filename)
{
    const char *point = filename; 
    const char *newName = malloc(sizeof(filename-5));

    if((point = strrchr(filename,'.palz')) != NULL ) 
    {   
        if(strstr(point,".palz") == 0) 
        {
          strncpy(newName, filename, strlen(filename)-5); 
          printf("%s\n",newName );     // the name shows correctly
          return newName;              // Segmentation fault (core dumped)
        }
    }
    return point;
}

该函数名为char checkExtensions(const char *filename)。由于我在网上找到的解决方案,我添加了const,但到目前为止我还没有能够使它工作...
提前感谢您的帮助!

5 个答案:

答案 0 :(得分:3)

您的代码存在许多问题。以下是其中一些:

  1. 您的函数返回char这是一个单个字符。您需要返回一个指向字符数组的指针,即C字符串。
  2. 您没有分配适量的内存。您在指针上使用sizeof(),这会产生指针的大小。
  3. 您使调用者无法知道是否释放内存。有时你堆分配,有时不分配。你的方法会泄漏。
  4. 您将'.palz'(一个字符文字)传递给strrchr,该char需要一个'.'。您的意思是#include <string.h> #include <stdio.h> void GetNewFileName(const char *fileName, char *newFileName) { const char *dot = strrchr(fileName, '.'); if (dot) { if (strcmp(dot, ".palz") == 0) { size_t len = dot - fileName; memcpy(newFileName, fileName, len); newFileName[len] = 0; return; } } size_t len = strlen(fileName); memcpy(newFileName, fileName, len); newFileName[len] = 0; return; } int main(void) { char fileName[256]; char newFileName[256]; strcpy(fileName, "foo.bar"); GetNewFileName(fileName, newFileName); printf("%s %s\n", fileName, newFileName); strcpy(fileName, "foo.bar.palz"); GetNewFileName(fileName, newFileName); printf("%s %s\n", fileName, newFileName); strcpy(fileName, "foo.bar.palz.txt"); GetNewFileName(fileName, newFileName); printf("%s %s\n", fileName, newFileName); return 0; }
  5. 更好的方法是让调用者分配内存。这是一个完整的程序,展示了如何:

    strcmp

    <强>输出

    foo.bar foo.bar
    foo.bar.palz foo.bar
    foo.bar.palz.txt foo.bar.palz.txt
    

    请注意{{1}}将敏感与字母大小写进行比较。在Windows上,文件名对大小写不敏感。我将把这个问题留给你处理。

    通过让调用者分配内存,允许他们选择分配内存的位置。如果愿意,他们可以使用本地堆栈分配缓冲区。调用者分配内存很容易,因为新文件名永远不会超过原始文件名。

答案 1 :(得分:1)

这很可能是你的问题:

const char *newName = malloc(sizeof(filename-5));

首先,filename的类型为const char *,这意味着(filename - 5)也属于此类型。因此,sizeof(filename - 5)将始终返回架构的指针数据类型的大小(x32为4,x64为8)。 因此,根据您的体系结构,您要拨打malloc(4)malloc(8)

其余的代码甚至无法编译,并且它有严重的字符串操作问题,所以很难说出你的目标是什么。我想strncpy()正在将过多的数据复制到newName缓冲区中,导致缓冲区溢出。

如果您的目标是从路径中提取文件名,那么您应该只使用char *basename(char *path)

答案 2 :(得分:0)

您的代码存在几个相当严重的问题。在我输入时进行补充,因此它可能无法立即第一次修复所有内容。忍受我。

  1. 您需要返回char *,而不是char

    const char checkExtension(const char *filename)
    {
        const char *point = filename; 
    
  2. malloc内存,但指令流并不能保证它会被释放或返回。

  3. sizeof(filename)应为strlen(filename),减去5( sans 扩展名),但+1(终止为0)。

        const char *newName = malloc(sizeof(filename-5));
    
  4. strrchr搜索单个字符。有些编译器允许“多字节字符常量”,但是他们期望像2那样 - 而不是 5 。由于您知道字符串的长度和开头,因此请使用strcmp。 (首先确保 至少5个字符。如果没有,则无论如何都不用于测试。)

        if((point = strrchr(filename,'.palz')) != NULL ) {  
    
  5. 呃,strstr在字符串中搜索字符串,如果找不到则返回0(实际上是NULL)。这与您之前的测试相矛盾。删除它。

        if(strstr(point,".palz") == 0)
        {
    
  6. strncpy复制n个字符,但如果没有复制,那么着名的(和记录的)不会添加终止0。你自己必须这样做。

  7. ..这实际上是malloc行应该出现的地方,就在使用返回之前。

              strncpy(newName, filename, strlen(filename)-5);
              printf("%s\n",newName ); // the name shows correctly
              return newName; // Segmentation fault (core dumped)
          }
        }
    
  8. 您在此处返回原始字符串。你怎么知道你需要free呢?如果您覆盖之前的 char *,其内存将会丢失。最好返回原始字符串的副本(因此可以随时释放它),或者,如我所愿,返回NULL以指示调用例程“不需要进一步操作”。

        return point;    
    }
    
  9. 希望我没有忘记任何事情。

答案 3 :(得分:0)

您的代码存在一些问题:

  • 错误的退货类型:

    const char checkExtension(const char *filename){
    

    您需要返回指针(const char *),而不是单个字符。

  • 内存不足:

    const char checkExtension(const char *filename){
    
      const char *newName = malloc(sizeof(filename-5));
    

    您正在分配指针大小char *),通常为4或8.您需要致电strlen()以找出大小字符串

  • 多字节字符:

    if((point = strrchr(filename,'.palz')) != NULL ) {  
    

    '.palz'是一个多字节字符文字。虽然在C中允许这样做,但它的值是实现定义的,可能无法达到您的预期。字符串文字使用 double 引号(".palz")。

  • 没有终止零:

    strncpy(newName, filename, strlen(filename)-5); 
    

    请注意,strncpy()不一定是空终止目标字符串。它最多写 strlen(filename)-5个字符。如果源字符串包含更多字符(如您的情况),则将写入终止零。


我不确定你到底要做什么。也许是这样的:

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

const char *checkExtension(const char *filename)
{
  int len = strlen (filename)-5;
  char *newName = NULL; /* return NULL on allocation failure. */

  if (len > 0 && !strcmp (filename+len, ".palz")) {
    newName = malloc (len+1);
    if (newName) {
      memcpy (newName, filename, len);
      newName[len] = 0;
    }
  }

  return newName;
}

int main (int ac, char **av)
{
  if (ac > 1) {
    const char *p = checkExtension (av[1]);
    puts (p ? p : "NULL");
  } else {
    puts ("?");
  }

  return 0;
}

答案 4 :(得分:0)

这里有多个错误。你还没有说过你想要实现的目标,这必须从代码中暗示。您已将pointnewName声明为const,但已使用值重新分配。您已对strstr() == 0进行了strstr() == NULL测试。您已调用strrchr(filename,'.palz')但发送了一个字符串而不是char。然后,在有机会使用之前,您已经返回了超出范围的局部变量point,因为它未被声明为静态。因此,无论是返回char还是char指针都无关紧要。

char *checkExtension(const char *filename) {
    // if filename has extension .palz return a pointer to
    // the filename stripped of extension or return NULL
    char *point;
    static char newName[512];
    strncpy(newName, filename, 512);
    if ((point = strstr(newName, ".palz")) != NULL ) {
        if (strlen (point) == 5) {
            *point = 0; // string terminator
            // printf("%s\n",newName ); // use only for debugging
            return newName;
        }
    }
    return NULL;
}

或者提供一个函数可以修改的字符串 -

char *checkExtension(const char *filename, char *newName) { ... }

或者提供函数可以修改的文件名 -

char *checkExtension(char *filename) {
    char *point;
    if ((point = strstr(filename, ".palz")) != NULL ) {
        if (strlen (point) == 5) {
            *point = 0; // string terminator
            return filename;
        }
    }
    return NULL;
}