Почему мы не можем скопировать строку в Символьный Указатель, КОГДА мы можем присвоить строку непосредственно ему?

Этот код производит "p = привет мир":

#include "stdio.h"
#include "string.h"

int main(){
    char *p;
    p="hello world";
    printf("p is %s \n",p);
    return 0;
}

Но этот код производит отказ сегментации:

#include "stdio.h"
#include "string.h"

int main() { 
    char *p;
    strcpy(p,"hello");
    printf("p is %s \n",p);
    return 0;
}

и этот код производит "p = привет"

#include "stdio.h"
#include "string.h"
#include "stdlib.h"
int main() {
  char *p;
  p=(char*)malloc (10);
  strcpy(p,"hello");
  printf("p is %s \n",p);
  return 0;

}

5
задан Cœur 8 December 2018 в 16:22
поделиться

7 ответов

В случае, когда p = "hello world"; (1-й случай на момент редактирования), p инициализируется для указания на доступную только для чтения область памяти, которая содержит строку «hello world» (строковый литерал). Эта доступная только для чтения область памяти создается во время компиляции.

В случае, который вызывает ошибку сегментации (2-й случай на момент редактирования), p не инициализируется, и копирование чего-либо в него приведет к непредсказуемым результатам, потому что место в памяти, которое p указывает на не указано в коде.

Прежде чем вы сможете скопировать строку в p , вы должны указать память, на которую указывает p .

Вы можете выделить эту память в стеке

char buf [BUFSIZ] = ""; / * локальная переменная * /

в куче

char * buf = malloc (BUFSIZ); / * не забудьте освободить * /

или в сегменте __DATA.

статический символ буфера [BUFSIZ] = ""; / * глобальная переменная * /

Затем вы можете инициализировать p , чтобы указать на буфер памяти.

char * p = buf;

Это похоже на концепцию инициализации p для указания на строковый литерал в постоянной памяти только для чтения. В отличие от случая, когда p указывает на строковый литерал, теперь вы можете скопировать строку в указатель символа, поскольку он не указывает на постоянную память .

Примечание: Я намеренно создал отдельный буфер и инициализировал p , чтобы указать на него, чтобы выразить мою точку зрения.

12
ответ дан 18 December 2019 в 06:22
поделиться

asset.url возвращает URL-адрес в файл. Обычно это /system/classname/xx/xx/style/filename.ext . Вы бы поместили это в изображение _ тэг .

Требуется asset.path . Он возвращает полный путь к файлу, который обычно имеет вид /home/username/railsapp/public/system/classname/xx/xx/style/filename.ext

HTH.

-121--3235754-

Нет бесплатного обеда - нужно захватить и управлять памятью. Если вы просто предполагаете, что, поскольку у вас есть доступ к памяти указателей должен быть там, то вы столкнетесь с неопределенным поведением (сегфо вероятно).

-121--4557573-

Причина в том, что при объявлении указателя он фактически не указывает ни на что полезное. strcpy требует блока памяти для копирования последовательности в. Он не будет делать это для вас автоматически.

Из документации (акцент мой):

Копирует последовательность C, указываемую источником в массив, указанный пунктом назначения, включая завершающее значение null персонаж.

Во избежание переполнения размер массив, указанный пунктом назначения, должен быть достаточно длинная, чтобы содержать один и тот же C последовательность в качестве источника (включая завершающий символ null) , и не должен перекрываться в памяти с источник.

Вы должны сделать это верным, так как это является предварительным условием функции.

Кроме того, в разделе параметров

назначение

 Указатель на целевой массив, в который должно быть скопировано содержимое.

Необходимо убедиться, что destination является указателем на массив.

5
ответ дан 18 December 2019 в 06:22
поделиться

Вместо того, чтобы задавать атрибут каскада, я думаю, что перед удалением книги нужно просто очистить коллекцию ReliveBooks.

book.RelatedBooks.Clear();
session.Delete(book);

Каскадное удаление обычно не выполняется в отношении «многие ко многим», поскольку оно удаляет объект на другом конце отношения, в данном случае книгу.

-121--3409494-

asset.url возвращает URL-адрес в файл. Обычно это /system/classname/xx/xx/style/filename.ext . Вы бы поместили это в изображение _ тэг .

Требуется asset.path . Он возвращает полный путь к файлу, который обычно имеет вид /home/username/railsapp/public/system/classname/xx/xx/style/filename.ext

HTH.

-121--3235754-

Бесплатный обед отсутствует - необходимо захватить и управлять памятью. Если вы просто предполагаете, что, поскольку у вас есть доступ к памяти указателей должен быть там, то вы столкнетесь с неопределенным поведением (сегфо вероятно).

2
ответ дан 18 December 2019 в 06:22
поделиться

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

Если вы абсолютно хотите избежать распределения динамической памяти и , вы знаете размер исходной строки во время компиляции , вы можете получить соответствующее пространство стека следующим образом:

char buffer[6]; /* strlen( "hello" ) + 1 for zero terminator */
strcpy( buffer, "hello" );

Но это опасная дорога, ведущая к переполнению буфера .

2
ответ дан 18 December 2019 в 06:22
поделиться

Обратите внимание на то, что общего у двух рабочих примеров: у них есть строка p = , которая присваивает что-то p . Нерабочий пример этого не делает.

Рассмотрим эту строку (из первого примера):

p = "hello world";

Хотя может показаться, что это «копирование строки в указатель на символ», это не так. Он копирует расположение строки в указатель на символ.Это то, что хранит указатель на символ типа p - расположение непрерывного блока из char s.

Точно так же рассмотрим эту строку из третьего примера:

p = malloc(10);

Это также копирование местоположения - это копирование местоположения блока из 10 неинициализированных char s в p .

strcpy (dest, source) копирует символы из местоположения, указанного в source , в местоположение, указанное в dest . Должно быть ясно, что если вы никогда не устанавливаете p в допустимое местоположение, тогда strcpy (p, "hello") не может сделать ничего разумного - во втором примере p является по сути случайным местом, и затем вы просите strcpy () скопировать что-нибудь в это место.

2
ответ дан 18 December 2019 в 06:22
поделиться

Копирование в память состоит из двух частей. Первый - это память, занятая элементом, который вы хотите скопировать (который вы создаете в своем примере с помощью функции malloc ()), а второй - указатель на этот блок памяти (который вы называете p). Эти две сущности также должны быть настроены для места назначения, прежде чем вы сможете сделать копию. В вашем первом неудачном примере вы не настроили блок памяти для места назначения (но он был установлен для источника неявно, когда вы объявляете строку hello ).

1
ответ дан 18 December 2019 в 06:22
поделиться

Да, это раздражает. Вы можете использовать strdup , чтобы сократить его:

char *p = strdup("hello");
printf("p is %s \n",p);
1
ответ дан 18 December 2019 в 06:22
поделиться
Другие вопросы по тегам:

Похожие вопросы: