2014-10-20 3 views
-2

Я получаю дамп ядра, который у меня нет, как решить. Я искал другие вопросы и гугле мою проблему, но я просто не могу понять, как решить эту проблему ...Вернуть строку на C

Вот код:

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 из-за тех решений, которые я нашел в Интернете, но до сих пор мне не удалось заставить его работать ...
Заранее благодарю за помощь!

+1

Строки представлены «символ *» или «сопзЬ полукокса * "в C. Ваша функция, как написано, возвращает символ" const char "(обратите внимание на отсутствие указателя). –

+0

@JoshPetrie, поэтому я не могу вернуть символ? Я должен вернуть его из ссылки? –

+0

Возвращение 'char' - это всего лишь один символ. – thelaws

ответ

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; 
} 

Выхода

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

Обратите внимание, что strcmp сравнивает чувствителен к строчным и заглавным буквам. В именах файлов Windows нечувствительны к случаю. Я оставлю эту проблему для вас.

Позволяя абоненту выделять память, вы позволяете им выбирать, где выделена память. Они могут использовать локальный стек, назначенный буфером, если захотят. И для вызывающего абонента легко выделять память, потому что новое имя файла никогда не превышает оригинальное имя файла.

+0

Спасибо за ответ, можете ли вы просто объяснить мне, что означает «size_t len ​​= dot - fileName;»? Почему это dot-fileName, а не fileName - точка? Спасибо за ваше время! –

+1

Поскольку точка больше имени файла, это адрес последнего периода в строке. –

+0

Это больше, потому что имя файла указывает адрес первой буквы имени файла, а точка указывает на адрес «.», Поэтому он делает точку большей, правильно? –

1

Это, скорее всего, ваша проблема:

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

Во-первых, имя файла типа const char *, что означает, что (filename - 5) также этого типа. Таким образом, sizeof(filename - 5) всегда будет возвращать размер типа указателя вашей архитектуры (4 для x32, 8 для x64). Итак, в зависимости от вашей архитектуры вы вызываете либо malloc(4), либо malloc(8).

Остальная часть кода даже не компилируется, и у него серьезные проблемы с манипулированием строкой, поэтому трудно сказать, на что вы нацелились. Я полагаю, что strncpy() копировал слишком много данных в буфер newName, что вызвало переполнение буфера.

Если ваша цель состояла в том, чтобы извлечь имя файла из пути, то вам, вероятно, следует использовать только char *basename(char *path).

0

Несколько довольно серьезных проблем с вашим кодом. Составляя это, когда я печатаю, поэтому он может не исправить все первый раз прямо сейчас. Потерпите меня.

  1. Вам нужно возвращать char *, не char.

    const char checkExtension(const char *filename) 
    { 
        const char *point = filename; 
    
  2. Вы malloc памяти, но поток инструкций не гарантирует, что будет освобожден или возвращен.

  3. sizeof(filename) должно быть strlen(filename), минус 5 (без расширения), но +1 (с нагрузочным 0).

    const char *newName = malloc(sizeof(filename-5)); 
    
  4. strrchr ищет один символ. Некоторые компиляторы допускают «многобайтовые символьные константы», но они ожидают чего-то вроде 2 - не пять. Поскольку вы знаете длину и начало строки, используйте 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;  
    } 
    

Надеется, что я ничего не забыл.

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; 
} 
0

Несколько ошибок здесь. Вы не сказали, чего вы пытаетесь достичь, что должно подразумеваться в коде. Вы объявили point и newName как const, но переназначены со значением. Вы проверили strstr() == 0, когда это должно быть strstr() == NULL. Вы вызвали strrchr(filename,'.palz'), но отправили строку вместо символа. Затем вы вернете локальную переменную 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; 
} 
Смежные вопросы