Почему этот код для изменения строки не работает?

С строками c-style, как вы назначаете char адресу памяти, на который указывает указатель на символ? Например, в приведенном ниже примере я хочу изменить num на "123456", поэтому я попытался установить p на цифру, где находится "0", и я пытаюсь перезаписать ее "4". Спасибо.

#include <stdio.h>
#include <stdlib.h>

int main()
{
    char* num = (char*)malloc(100);
    char* p = num;

    num = "123056";

    p = p+3;    //set pointer to where '4' should be
    p = '4';

    printf("%s\n", num );

    return 0;
}

Ответы

Ответ 1

Этот код не будет работать, просто потому, что строка:

num = "123056";

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

Вам нужно следующее:

#include <stdio.h>
#include <stdlib.h>
int main (void) {
    char *num = malloc (100); // do not cast malloc return value.
    char *p = num;

    strcpy (num, "123056");   // populate existing block with string.

    p = p + 3;                // set pointer to where '0' is.
    *p = '4';                 // and change it to '4'.

    printf ("%s\n", num );    // output it.

    return 0;
}

Ответ 2

Прежде всего, когда вы это сделаете:

num = "123056";

Вы не копируете строку "123056" в область кучи, выделенную malloc(). В C, назначая указатель char *, строковое литеральное значение эквивалентно установке его как константы, то есть идентичного:

char str[] = "123056";

Итак, что вы только что достигли, вы отказались от своей единственной ссылки на 100-байтовую кучу, выделенную malloc(), поэтому ваш следующий код не печатает правильное значение; 'p' все еще указывает на область кучи, выделенную malloc() (поскольку num указал на нее во время назначения), но num больше не делает.

Я предполагаю, что вы на самом деле намеревались сделать это, чтобы скопировать строку "123056" в эту область кучи. Вот как это сделать:

strcpy(num, "123056");

Хотя это лучше по целому ряду причин:

strncpy(num, "123056", 100 - 1);  /* leave room for \0 (null) terminator */

Если вы только что сделали:

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

int     main(void) {
        char    *num = malloc(100);
        char    *p = num;

        strncpy(num, "123056", 100 - 1);

        p = p + 3;
        *p = '4';

        printf("%s\n", num);

       return 0;
} 

Вы получили бы правильный результат:

123456

Вы можете сжимать эту операцию:

p = p + 3;
*p = '4';

... и избегать повторения указателя, отсрочив следующим образом:

*(p + 3) = '4';

Несколько других примечаний:

  • Хотя общая стилистическая практика, отбрасывание возвращаемого значения от malloc() до (char *) не требуется. Преобразование и выравнивание типа void * гарантируется языком C.

  • ВСЕГДА проверяем возвращаемое значение malloc(). Это будет NULL, если распределение кучи не удалось (т.е. Вы потеряли память), и в этот момент ваша программа должна выйти.

  • В зависимости от реализации область памяти, выделенная malloc(), может содержать устаревший мусор в определенных ситуациях. Всегда полезно обнулить его после выделения:

    memset(num, 0, 100);
    
  • Никогда не забывайте free() свою кучу! В этом случае программа выйдет, и ОС очистит ваш мусор, но если вы не привыкнете, вы мгновенно потеряете память.

Итак, вот версия "лучшей практики":

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

int     main(void) {
        char    *num, *p;

        /*
         * Don't take 1-byte chars for granted - good habit to get into.
         */

        num = malloc(sizeof(char) * 100);

        if(num == NULL)
                exit(1);

        memset(num, 0, sizeof(char) * 100);

        p = num;

        strncpy(num, "123056", 100 - 1);

        *(p + 3) = '4';

        printf("%s\n", num);

        free(num);

        return 0;
}

Ответ 3

В дополнение к проблеме * p, которую другие указали, у вас также есть проблемы с использованием памяти. У вас есть один буфер размером 100 байт с неизвестным содержимым. У вас есть еще один буфер из 7 байтов, содержащий строку "123056" и нулевой терминатор. Вы делаете это:

  • num задано значение для 100-байтового буфера
  • p задано значение num; т.е. он указывает на 100-байтовый буфер
  • вы reset num укажете на 7-байтовый буфер; p все еще указывает на 100-байтовый буфер
  • Вы используете p для изменения буфера в 100 байт
  • то вы используете num для печати 7-байтового буфера

Итак, вы не печатаете тот же буфер, который вы изменяете.

Ответ 4

Просто используйте *p = '4';...!

Ответ 5

Ну, вы знаете, что p - тип указателя. Он сохраняет адрес char '0'. Если вы присвоите p значение "4" . В качестве адреса будет указано "4" . Однако адрес "4" является незаконным. Вы можете использовать оператор '*', чтобы получить значение, которое хранится в памяти.