Почему этот код для изменения строки не работает?
С строками 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" является незаконным. Вы можете использовать оператор '*', чтобы получить значение, которое хранится в памяти.