В чем разница между использованием strcpy и приравниванием адресов строк? - PullRequest
1 голос
/ 16 июня 2019

Я не могу понять разницу между функцией strcpy и методом выравнивания адресов строк с помощью указателя. Код, приведенный ниже, прояснит мою проблему.Любая помощь будет оценена.

//code to take input of strings in an array of pointers
#include <stdio.h>
#include <strings.h>
int main()
{
    //suppose the array of pointers is of 10 elements
    char *strings[10],string[50],*p;
    int length;
    //proper method to take inputs:
    for(i=0;i<10;i++)
    {
        scanf(" %49[^\n]",string);
        length = strlen(string);
        p = (char *)malloc(length+1);
        strcpy(p,string);//why use strcpy here instead of p = string
        strings[i] = p; //why use this long way instead of writing directly strcpy(strings[i],string) by first defining malloc for strings[i]
    }
return 0;
}

Ответы [ 3 ]

1 голос
/ 16 июня 2019
char *strings[10]---- --------->1.
strcpy(strings[i],string) ----->2.
strings[i] = string ----------->3.


p = (char *)malloc(length+1); -|
strcpy(p,string);              |-> 4.
strings[i] = p;----------------|
  1. strings - это массив указателей, каждый указатель должен указывать на действительную память.

  2. приведет к неопределенному поведению, поскольку strings[i] не указывает на действительную память.

  3. Работает, но каждый указатель strings будет указывать на одно и то же местоположение, поэтому у каждого будет одинаковое содержимое.
  4. Таким образом, сначала создайте новую памятьскопируйте туда содержимое и назначьте эту память на strings[i]
1 голос
/ 16 июня 2019

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

strcpy(char *destination, char *source);

копирует из источника в место назначения, пока функция не найдет '\ 0'.Эта функция небезопасна и не должна использоваться - попробуйте strncpy или strlcpy.Вы можете найти полезную информацию об этих двух функциях в https://linux.die.net/man/3/strncpy - проверьте, где будет выполняться ваш код, чтобы помочь вам выбрать лучший вариант.

В вашем блоке кода у вас есть это объявление

char *strings[10],string[50],*p;

Здесь объявляются три указателя, но они совершенно разные.*p - обычный указатель, и для него должно быть выделено пространство (через malloc), прежде чем вы сможете его использовать.string[50] также является указателем, но длиной 50 (символы, обычно 1 байт) - и он размещается непосредственно в стеке функций, так что вы можете использовать его сразу (хотя самое первое его использование должноОбнулять память, если вы не использовали распределитель обнуления, такой как calloc в Solaris. Наконец, *strings[10] - это указатель double - вы выделили массив из 10 указателей, каждый элемент которого(strings[1], strings[9] и т. Д.) Должны быть выделены для использования перед использованием.

Единственный из тех, кому вы можете назначить немедленно, это string, потому что пространство уже выделено. Каждый из этих указателейможет быть решена с помощью подписки - но в каждом случае вы должны убедиться, что вы не ушли с конца, иначе вы столкнетесь с «нарушением сегментации» SIGSEGV, и ваша программа будет аварийно завершена.просто странные результаты.

Наконец, выделенные указатели должны быть освобождены вручную, иначе у вас будут утечки памяти. Элементы, выделенные в стеке (string) освобождать не нужно, потому что компилятор обрабатывает это после завершения функции.

1 голос
/ 16 июня 2019

Краткое введение в магию указателей:

char *strings[10],string[50],*p;

Это три переменные с разными типами:

char *strings[10]; // an array of 10 pointers to char
char string[50]; // an array of 50 char
char *p; // a pointer to char

Затем выполняется повтор (10 раз):

    scanf(" %49[^\n]",string);

Считать строку C из входных данных и сохранить ее в string, учитывая, что терминатор 0 также должен уместиться.

    length = strlen(string);

Считать не 0 символов, пока не будет найден терминатор 0, и сохранитьв length.

    p = (char *)malloc(length+1);

Выделите память в куче длиной + 1 (для 0 терминатора) и сохраните адрес этой памяти в p.(malloc() может не сработать. Проверка if (p != NULL) не помешает.)

    strcpy(p,string);//why use strcpy here instead of p = string

Скопируйте строку C в string в память, указанную в p.strcpy() копирует до тех пор, пока в источнике не будет найден терминатор (включительно) 0.

    strings[i] = p;

Назначьте p (указатель на память) на strings[i].(После присвоения strings[i] указывает на ту же память, что и p. Назначение является назначением указателя, но не назначением значения, на которое указано.)


Почему strcpy(p,string); вместоp = string:

Последний назначит адрес string (локальная переменная, вероятно, хранится в стеке) для p.

  1. Адрес выделенногопамять (с malloc()) была бы потеряна.(Это приводит к утечке памяти - памяти в куче, которая не может быть решена ни одним указателем в коде.)

  2. p теперь будет указывать на локальную переменную в string (для каждогоитерация в цикле for).Следовательно, впоследствии все записи в strings[10] будут указывать на string наконец.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...