Есть ли способ сделать строки независимыми от других? - PullRequest
1 голос
/ 05 августа 2020

Это процесс моего кода.

  • получить строку scanf
  • сохранить строку в массиве arr
  • повторить эту работу

Вот мой код.

#include <stdio.h>

int main(void)
{
    char str[10];
    char * arr[10];

    for(int i=0; i<3; i++) {
        scanf("%s", str);
        arr[i] = str;
        printf("%s %p\n", arr[i], str);
    }
    for(int i=0; i<3; i++)
        printf("%s\n", arr[i]);
    return 0;
}

Результаты:

aaa
aaa 0x7ffee773892e
bbb
bbb 0x7ffee773892e
ccc
ccc 0x7ffee773892e
ccc
ccc
ccc

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

#include <stdio.h>

int main(void)
{
    char * str;  /* This line is changed. */
    char * arr[10];

    for(int i=0; i<3; i++) {
        scanf("%s", str);
        arr[i] = str;
        printf("%s %p\n", arr[i], str);
    }
    for(int i=0; i<3; i++)
        printf("%s\n", arr[i]);
    return 0;
}

Я изменил char str[10]char * str, чтобы не сохранять одинаковые строки. Очевидно, str указывает разные адреса для каждого l oop, но это все равно не работает.

#include <stdio.h>

int main(void)
{
    char * str;
    char * arr[10];

    for(int i=0; i<3; i++) {
        if (i == 0)
            str = "Hello";
        else if (i == 1)
            str = "World";
        arr[i] = str;
        printf("%s %p\n", arr[i], str);
    }
    for(int i=0; i<3; i++)
        printf("%s\n", arr[i]);
    return 0;
}

Результаты:

Hello 0x1074bbfa0
World 0x1074bbfa6
World 0x1074bbfa6
Hello
World
World

Однако это работает.

Я не знаю, чем отличается второе от третьего. Есть ли способ сделать строки независимыми от других?

+) fgets, get тоже были плохими.

Ответы [ 2 ]

2 голосов
/ 05 августа 2020

Проблема заключается в назначении

arr[i] = str;

Это не создает новую копию str, вместо этого arr[i] просто указывает на то место, куда указывает str (который является первым элемент массива str или &str[0]). И если вы сделаете это для всех элементов arr, тогда все элементы будут указывать на одно и то же место.

Если вы «нарисуете» его, это будет выглядеть примерно так:

+--------+
| arr[0] | --\
+--------+    \     +-----+
| arr[1] | ----+--> | str |
+--------+    /     +-----+
| arr[2] | --/
+--------+
| arr[3] | --> ???
+--------+
| ...... |
+--------+

[arr[3] и далее неинициализированные , они указывают на неопределенные местоположения]

Одно возможное (и простое) решение состоит в том, чтобы сделать arr не массивом указателей, а массивом массивов:

char arr[10][10];

Теперь каждый элемент arr является независимым массивом, который вы можете использовать в scanf

scanf("%9s", arr[i]);

[Обратите внимание на ограничение длины, добавленное в формат, чтобы не записывать за пределы массива]

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

И у него все еще есть та же проблема , что и в первой программе, где каждый из инициализированных указателей в arr указывает туда же!

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

Это означает, что "Hello" является массив из шести символов (включая нуль-терминатор), а "World" - это другой массив , полностью независимый от любого другого массива.

Это означает, что arr[0] будет указывать на первый символ массив для "Hello", arr[1] и arr[2] оба будут указывать на первый символ массива для "World".

Оба arr[1] и arr[2] будут указывать на одно и то же место потому что вы не изменяете str между второй и третьей итерацией.

1 голос
/ 05 августа 2020

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

int main(void)
{
    char str[10];
    char *arr[10];

    for(int i=0; i<3; i++) {
        scanf("%s", str);
        arr[i] = malloc(strlen(str) + 1);
        strcpy(arr[i], str);
        printf("%s %p\n", arr[i], str);
    }
    for(int i=0; i<3; i++)
        printf("%s\n", arr[i]);
    return 0;
}
int main(void)
{
    char str[10];
    char arr[10][10];

    for(int i=0; i<3; i++) {
        scanf("%s", str);
        strcpy(arr[i], str);
        printf("%s %p\n", arr[i], str);
    }
    for(int i=0; i<3; i++)
        printf("%s\n", arr[i]);
    return 0;
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...