2015-10-25 3 views
0

Тема говорит все, вот соответствующий код, написанный в простом файле.освобождение указателя char в c вызывает segfault

char* fn = NULL; 
SDL_Log("fn pre address is: %p\n",fn); 
fn = get_resource("test.txt"); 
SDL_Log("fn pos address is: %p\n",fn); 
//free(fn); <--this causes seg fault if I uncomment it 

INFO: fn pre address is: 0x0 
INFO: fn pre address is: 0x7fa882501a00 
INFO: fn pos address is: 0x7fa882501a00 

get_resource(const char* filename) { 
    char* string = (char*)calloc(1, sizeof(strlen(res_dir) + strlen(filename))); 
    //i also tried with strncpy 
    //strncpy(string, res_dir, strlen(res_dir)); 
    //strncpy(string + strlen(res_dir), filename, strlen(filename)); 

    memcpy(string, "/usr/test/files", strlen(res_dir)); 
    memcpy(string + strlen("/usr/test/files"), filename, strlen(filename)); 
    string[strlen(filename) + strlen("/usr/test/files")] = '\0'; 
    return string; 
} 

получение такого же поведения. Если я освобожу выделенную строку, я получу ошибку seg. Кроме того, это не всегда случается так странно.

+0

OT: 'string' - это плохое имя, также оно вводит в заблуждение, так как это * указатель * на первый элемент (символ здесь) памяти, выделенной вызовом' calloc() '. – alk

+0

@alk также OT, но я считаю, что 'string' является очень подходящим именем для символа' char * '. –

+0

@MrLister на некотором уровне абстракции, 'string' достаточно хорошо описывает, что означает' char * ', если он указывает на« C-строку ». Но я с @alk здесь по двум причинам: 1.) «Строка C» - это последовательность байтов, а не указатель на нее - последовательность будет часто оценивать указатель (если это массив или если вы просто используйте строковый литерал *) и 2.) именование переменной вроде этого просто не выразительно. Это похоже на запись 'int myInt = 42;' - отлично, что вы делаете из * этого * при чтении кода? –

ответ

2

Прежде всего это заявление

char* string = (char*)calloc(1, sizeof(strlen(res_dir) + strlen(filename))); 

неверен. Выражение

sizeof(strlen(res_dir) + strlen(filename)) 

эквивалентно

sizeof(size_t) 

и может быть равным 4 или 8 в зависимости от используемой среды.Более этого выражения

sizeof(strlen(res_dir) + strlen(filename)) 

является невычисленного. То есть функция strlenне называется в этом выражении.

Правильное утверждение может выглядеть

char *string = calloc(strlen(res_dir) + strlen(filename) + 1, sizeof(char)); 

Возьмите в АСоип, что вам нужно также зарезервировать память для завершения ноля.

Однако даже это утверждение неверно. :)

Подумайте, что вы пытаетесь сделать

memcpy(string, "/usr/test/files", strlen(res_dir)); 
memcpy(string + strlen("/usr/test/files"), filename, strlen(filename)); 

Как вы прошли строку "test.txt", то вы получите

"/usr/test/filestest.txt" 

Я думаю, что вы означает следующее:

"/usr/test/files/test.txt" 

Если да, то распределение памяти должно выглядеть

char *string = calloc(strlen(res_dir) + strlen(filename) + 2, sizeof(char)); 

В этом случае вы можете просто написать

strcpy(string, "/usr/test/files"); 
strcat(string, "/"); 
strcat(string, filename); 

и в этом случае заявление

string[strlen(filename) + strlen("/usr/test/files")] = '\0'; 

должны быть удалены.

+0

Хмм не уверен, что с этим делать? Приятно видеть, что вы разъясняете, что «sizeof (strlen ([foo])) на самом деле будет оценивать и также выработать немного более четко, почему в результате результирующего пути может отсутствовать косая черта ... но действительно ли вам нужно было дать в основном тот же ответ снова? Ну, все равно, так как есть * какое-то объяснение, я не включил себя. –

8
char* string = (char*)calloc(1, sizeof(strlen(res_dir) + strlen(filename))); 

Эта линия не делает любой смысл, sizeof является оператором для определения размера памяти, необходимый для типа или выражения какого-либо типа. (*)

Что вы хотите это что-то вроде:

Обратите внимание на + 1 там, она оставляет пространство для завершающего 0 байта в строке с стилем. Также обратите внимание на литье указателя void * (как было возвращено malloc() и друзьями в C) не имеет смысла. Это необходимо в C++, но в C void * - это общий указатель типа и неявно преобразуется в любой другой тип указателя данных.

Копаем дальше в ваш код (согласно замечанию алка) ... Думаю, res_dir всего лишь "/usr/test/files"? Здесь может отсутствовать косая черта (в зависимости от содержимого вашего filename), но в целом для конкатенации строк уже существует функция на языке C, объявленная в string.h. Просто напишите что-то простое:

char* string = calloc(1, strlen(res_dir) + strlen(filename) + 1); 
strcpy(string, res_dir); 
strcat(string, filename); 

и все готово. Обратите внимание, что вам не нужен calloc() с этим методом, malloc() все будет в порядке.


(*), добавив здесь даже немного больше объяснений: Вы, вероятно, увидеть sizeof довольно часто используется при распределении памяти, по понятным причинам. Вы хотите зарезервировать память для типа char. И вам нужно подсчитать char s, чтобы вписаться в эту память. Таким образом, правильная формула для этого было бы что-то вроде:

malloc((strlen(res_dir) + strlen(filename) + 1) * sizeof(char)) 

Тогда почему оставить из sizeof(char)? Это потому, что размер char фактически равен будет 1. x * 1 все еще x, поэтому нет необходимости использовать sizeof здесь :)

+1

Возможно, стоит упомянуть, что предпочтительный способ конкатенации C-"строк" - использовать 'strcat()'. – alk

+0

@ не сомневаюсь, это не входит в сферу моего вопроса, но у меня будет второй взгляд - спасибо. –

+1

@alk, и, таким образом, небольшой прямой ответ вырос до чего-то вроде «струнного и динамического распределения, обрабатывающего праймер» ... хе-хе. Надеюсь, что это поможет OP, спасибо за намек на это. –

Смежные вопросы