Модераторы: bsa
  

Поиск:

Ответ в темуСоздание новой темы Создание опроса
> копирование указателей 
:(
    Опции темы
grisWall
Дата 6.9.2013, 11:49 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Новичок



Профиль
Группа: Участник
Сообщений: 18
Регистрация: 28.4.2013

Репутация: нет
Всего: нет



Всем доброго времени суток у меня назрел вопрос. Я решил тут на днях написать программку на Си которая принимает в консоли параметры и создает папку с именем и помещает в неё main.c. Что то типа начальный шаблон для автоматизации создания программ в отдельных папках, а то я тут глянул один раз и ужаснулся что у меня в одной папке столько программ и столько  хлама что в пору уже вешаться чем со всем этим разобраться. Я решил написать программку и вроде написал я ее и она мне все создавала. Но вот не задача решил, я начитавшись K&R переписать её указателями. И тут я попал на такую вещь как ошибка сигментирования я то ее реализовал массивами и горя не знал а вот как только я начал делать 
Код

const char * fileName = "main.c";
char file[] = "\t*                       *";
for (i = 0; (k = fileName[i]) != '\0'; i++)
file[3+i] = k;
 с  указателями, 
Код

const char * fileName = "main.c";
char * file = "\t*                      *";
for (i = 0; ((k = *fileName) != '\0'); i++)
fileName++;
*(file + 3 + i) = k;
тогда тут же на меня посыпались камни в виде ошибок сигментирования.

и дальше хуже кто-нибудь объясните мне, почему вот такой код вызывает ошибку сигментирования?

Код

const char * fileName = "main.c"
char * file = "\t*                                *";

file = strcpy (file, fileName);


при том что все это компилируется молча.

Это сообщение отредактировал(а) grisWall - 6.9.2013, 12:05
PM MAIL   Вверх
leshiysoft
Дата 6.9.2013, 11:58 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Новичок



Профиль
Группа: Участник
Сообщений: 19
Регистрация: 3.8.2007

Репутация: нет
Всего: нет



Если просто, то так: 
Потому что в Ваше переменной file лежит указатель на константную строку в сегменте данных, так как вы её задаете прямо в коде. Други словами в куче место под эту переменную не выделялось и аллоков и маллоков небыло. Вот она и ругается, мол, в сегмент данных, содержимое которого формируется в процессе компиляции, нехорошо писать. Нужно руками выделять необходимый объем памяти.
PM MAIL ICQ   Вверх
grisWall
Дата 6.9.2013, 12:08 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Новичок



Профиль
Группа: Участник
Сообщений: 18
Регистрация: 28.4.2013

Репутация: нет
Всего: нет



Цитата(leshiysoft @  6.9.2013,  11:58 Найти цитируемый пост)
Если просто, то так:


а если по конкретнее?

PM MAIL   Вверх
leshiysoft
Дата 6.9.2013, 13:41 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Новичок



Профиль
Группа: Участник
Сообщений: 19
Регистрация: 3.8.2007

Репутация: нет
Всего: нет



Правильно так:
Код

const char * fileName = "main.c";
char * file = (char*) malloc (7);
file = strcpy (file, fileName);
free (file);


Все дело в том, что любая строка в кавычках используемая в коде - это const char*, причем располагается она в секторе данных для чтения. Следовательно, записывать в неё нельзя. Для записи нужно вручную выделить память, например, так:
Код

char * file = (char*) malloc (7);


и незабыть очистить память:
Код

free (file);


Кстати можно было не вводить новую переменную fileName и использовать строку в кавычках прямо в аргументах функции strcpy:
Код

char * file = (char*) malloc (7);
file = strcpy (file,  "main.c");
free (file);

так как она (строка в кавычках) имеет нужный для strcpy тип : const char*
PM MAIL ICQ   Вверх
feodorv
Дата 6.9.2013, 13:44 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
****


Профиль
Группа: Комодератор
Сообщений: 2214
Регистрация: 30.7.2011

Репутация: 12
Всего: 45



Цитата(grisWall @  6.9.2013,  13:08 Найти цитируемый пост)
а если по конкретнее?

Цитата(grisWall @  6.9.2013,  12:49 Найти цитируемый пост)
char * file = "\t*                                *";

Переменная file указывает на область в памяти процесса, в которой находятся символы '\t', ' ' ... ' ', '*', '\0'
Проблема в том, что эта область памяти защищена от записи. Так её создал и определил компилятор, что вполне корректно, ибо строковый литерал по своей сути - константа.
Более того, если Вы создадите ещё одну подобную переменную, указывающую на ту же самую строку:
Код
char * file = "\t*                                *";
char * filo = "\t*                                *";
то вполне может оказаться так, что значения file и filo (то есть адреса строк) совпадают (то есть они указывают на одну и туже область памяти, а не на разные, но с одинаковым содержанием).

Что делать? Самый простой способ - это воспользоваться инициализированным массивом:
Код
char fileBuf[100] = "\t*                                *";
char *file = fileBuf;
Тогда уже file будет указывать на изменяемую область памяти.

Добавлено через 2 минуты и 17 секунд
Цитата(leshiysoft @  6.9.2013,  14:41 Найти цитируемый пост)
char * file = (char*) malloc (7);

А без выделения памяти никак???

Добавлено через 5 минут и 30 секунд
Цитата(feodorv @  6.9.2013,  14:44 Найти цитируемый пост)
Тогда уже file будет указывать на изменяемую область памяти.

Да, нужно заметить, что эта изменяемая память ограничена в размерах - 100 байт и не более. В случае выхода за её пределы:
Код
file[100] = ' ' ;
возможен очередной SIGSEGV, а если он не произойдет, то всё равно это приведёт к непредсказуемому поведению программы.


--------------------
Напильник, велосипед, грабли и костыли - основные инструменты программиста...
PM MAIL   Вверх
leshiysoft
Дата 6.9.2013, 13:50 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Новичок



Профиль
Группа: Участник
Сообщений: 19
Регистрация: 3.8.2007

Репутация: нет
Всего: нет



Массив действительно подойдет, так как массив в С - это ничто иное как указатель. И память выделенную под массив не нужно очищать. Но в случае если размера массива вам будет нехватать надо будет переписывать и перекомпилировать программу. Особенно это неприятно и неправильно, когда необходимый размер под строку заранее неизвестен, например, зависит от размера строки введенной пользователем.
PM MAIL ICQ   Вверх
feodorv
Дата 6.9.2013, 14:13 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
****


Профиль
Группа: Комодератор
Сообщений: 2214
Регистрация: 30.7.2011

Репутация: 12
Всего: 45



Цитата(leshiysoft @  6.9.2013,  14:50 Найти цитируемый пост)
Но в случае если размера массива вам будет нехватать надо будет переписывать и перекомпилировать программу.

Это да. Довольно часто возникают задачи, в которых необходимый объём памяти заранее не известен. С другой стороны, на мой взгляд, ещё чаще программисты недооценивают возможность воспользоваться массивом)))

Но в любом случае придётся тщательно рассчитывать необходимый размер. Чаще всего, этот размер вполне комфортный и ограничен сверху разумной константой, так почему бы в таком случае не использовать массив? 

Тщательность определения необходимого размера памяти демонстрирует и этот пример:
Цитата(grisWall @  6.9.2013,  12:49 Найти цитируемый пост)
const char * fileName = "main.c";
char file[] = "\t*                       *";
for (i = 0; (k = fileName[i]) != '\0'; i++) file[3+i] = k;


Хорошо, что здесь sizeof("main.c")+3 меньше или равен чем sizeof("\t*                       *"). А если больше:
Код

const char * fileName = "/disk2/mount/v/usr/abracadabra/projects/my/k&r/test1/main.c"


Опять непонятный SIGSEGV?



--------------------
Напильник, велосипед, грабли и костыли - основные инструменты программиста...
PM MAIL   Вверх
grisWall
Дата 6.9.2013, 23:23 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Новичок



Профиль
Группа: Участник
Сообщений: 18
Регистрация: 28.4.2013

Репутация: нет
Всего: нет



да я кстати замечу что у меня то в коде изначально я реализовал массивами все это дело вот так: 
Код

char fileName[] = "main.c";
char prog[48] = "\t*                                                 *";    // сюда помещаем название программы
char file[48] = "\t*                                                  *";    // сода помещаем название файла
for (i = 0; (k = fileName[i]) != '\0')
   file[3+i] = k;
for (i = 0; (k = argv[0][i]) !='\0')
   prog[3+i] = k;


это я уже для эксперименту решил по пробовать получиться может изящнее или эффективнее вот и напробовался блин так что мама не горюй щас все вернул назад даже что-то доработал в старой версии. Так что всем спасибо за дельные советы все очень помогли особенно с malloc и free а по поводу определения размера у массива я тоже взял на заметку... спасибо.
Цитата




Это сообщение отредактировал(а) grisWall - 6.9.2013, 23:31
PM MAIL   Вверх
akizelokro
Дата 7.9.2013, 10:49 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Крокодил
**


Профиль
Группа: Участник
Сообщений: 761
Регистрация: 30.7.2007

Репутация: 1
Всего: 5



Цитата(grisWall @  6.9.2013,  23:23 Найти цитируемый пост)
// сода помещаем название файла

Смотри, есть системные требования, например, для максимальной длины названия файла (вместе с путём).
Вердикт. Массиву сразу присваешь такую размерность. Не экономь сотню байтов, зато потом ты лишний раз нигде не будешь удивлятьс. Это раз.





--------------------
a = a + b; b = a - b; a = a - b;
PM MAIL   Вверх
feodorv
Дата 7.9.2013, 11:43 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
****


Профиль
Группа: Комодератор
Сообщений: 2214
Регистрация: 30.7.2011

Репутация: 12
Всего: 45



Цитата(akizelokro @  7.9.2013,  11:49 Найти цитируемый пост)
Смотри, есть системные требования, например, для максимальной длины названия файла (вместе с путём).
Вердикт. Массиву сразу присваешь такую размерность. Не экономь сотню байтов, зато потом ты лишний раз нигде не будешь удивлятьс. Это раз.

Ну, тут немного другие требования. Готовится вывод на экран в "красивом" виде))) Следовательно, нужно не увеличивать буфер под возможности файловой системы, а ограничить длину имени файла:
Код

char prog[64] = "\t*                                                 *";    // сюда помещаем название программы
char file[64] = "\t*                                                  *";    // сода помещаем название файла
for (i = 0; i < 48 && (k = fileName[i]) != '\0'; ++i)
   file[3+i] = k;
for (i = 0; i < 48 && (k = argv[0][i]) !='\0'; ++i)
   prog[3+i] = k;


Кстати:
Цитата(grisWall @  7.9.2013,  00:23 Найти цитируемый пост)
char prog[48] = "\t*                                                 *";    // сюда помещаем название программы
char file[48] = "\t*                                                  *";    // сода помещаем название файла

48 байт явно мало для строки "\t*                                                  *" smile 


--------------------
Напильник, велосипед, грабли и костыли - основные инструменты программиста...
PM MAIL   Вверх
ТарасАтавин
Дата 7.9.2013, 12:26 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Опытный
**


Профиль
Группа: Участник
Сообщений: 370
Регистрация: 26.8.2013

Репутация: нет
Всего: нет



Цитата(grisWall @  6.9.2013,  11:49 Найти цитируемый пост)
Всем доброго времени суток у меня назрел вопрос. Я решил тут на днях написать программку на Си которая принимает в консоли параметры и создает папку с именем и помещает в неё main.c. Что то типа начальный шаблон для автоматизации создания программ в отдельных папках, а то я тут глянул один раз и ужаснулся что у меня в одной папке столько программ и столько  хлама что в пору уже вешаться чем со всем этим разобраться. Я решил написать программку и вроде написал я ее и она мне все создавала.
Вместо перемещения файлов средствами интерфейса системы конечно же надо дописать специальную прогу к имеющейся помойке, потом ещё одну для её запуска и передаче ей параметров, потом для её запуска и передаче параметров ей и так пока весь винт на это не изведёшь. Так держать.


--------------------
Не так всё плохо, как оно есть на самом деле.
PM MAIL   Вверх
akizelokro
Дата 7.9.2013, 12:49 (ссылка) |    (голосов:1) Загрузка ... Загрузка ... Быстрая цитата Цитата


Крокодил
**


Профиль
Группа: Участник
Сообщений: 761
Регистрация: 30.7.2007

Репутация: 1
Всего: 5



Руку на чем-то набивать ему надо


--------------------
a = a + b; b = a - b; a = a - b;
PM MAIL   Вверх
ТарасАтавин
Дата 7.9.2013, 13:34 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Опытный
**


Профиль
Группа: Участник
Сообщений: 370
Регистрация: 26.8.2013

Репутация: нет
Всего: нет



Цитата(feodorv @  7.9.2013,  11:43 Найти цитируемый пост)
Ну, тут немного другие требования. Готовится вывод на экран в "красивом" виде))) Следовательно, нужно не увеличивать буфер под возможности файловой системы, а ограничить длину имени файла:
А про терминальный ноль знаешь?



--------------------
Не так всё плохо, как оно есть на самом деле.
PM MAIL   Вверх
  
Ответ в темуСоздание новой темы Создание опроса
Правила форума "C/C++: Для новичков"
JackYF
bsa

Запрещается!

1. Публиковать ссылки на вскрытые компоненты

2. Обсуждать взлом компонентов и делиться вскрытыми компонентами

  • Действия модераторов можно обсудить здесь
  • С просьбами о написании курсовой, реферата и т.п. обращаться сюда
  • Вопросы по реализации алгоритмов рассматриваются здесь


Если Вам понравилась атмосфера форума, заходите к нам чаще! С уважением, JackYF, bsa.

 
0 Пользователей читают эту тему (0 Гостей и 0 Скрытых Пользователей)
0 Пользователей:
« Предыдущая тема | C/C++: Для новичков | Следующая тема »


 




[ Время генерации скрипта: 0.0528 ]   [ Использовано запросов: 22 ]   [ GZIP включён ]


Реклама на сайте     Информационное спонсорство

 
По вопросам размещения рекламы пишите на vladimir(sobaka)vingrad.ru
Отказ от ответственности     Powered by Invision Power Board(R) 1.3 © 2003  IPS, Inc.