скрытое меню

передача строки в функцию

Все ниже написанное проверялось под средой Atollic True Studio на контроллере STM32F205.

Строка это указатель на последовательность байт завершающихся '\0'. Поэтому самый логичный способ передавать строку в функцию как указатель на байты.

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

Передаем строку в функцию как указатель

void myFunction(uint8_t *str)
{
	printf(" myFunction str = %s \n" , str);
}

int main(void)
{
	uint8_t *str1 = "abc";
	printf(" str1 = '%s' \n" , str1);
	myFunction( str1 );

	uint8_t str2[]="abcd";
	printf(" str2 = '%s' \n" , str2);
	myFunction( str2 );

	uint8_t str3[]={'a','b','c','d','e','\0'};
	printf(" str3 = '%s' \n" , str3);
	myFunction( str3 );
}

 вывод : 
 str1 = 'abc' 
 myFunction str = abc 
 str2 = 'abcd' 
 myFunction str = abcd 
 str3 = 'abcde' 
 myFunction str = abcde 

Работаем с переданной строкой внутри функции

Работаем как с обычным указателем на массив байтов. Только заканчивается массив тогда - когда встречается символ '\0'.

void myFunction(uint8_t *str)
{
	printf(" myFunction str : " );

	for(uint8_t ii=0 ; ii < strlen(str); ii++)
		printf("%c" , str [ ii ] );

	printf("\n");

       //  myFunction str : abc

	printf(" myFunction str : " );

	for(uint8_t ii=0 ; ii < strlen( str ) ; ii++)
		printf("%c" , *( uint8_t* )( str + ii ));

	printf("\n");

       //  myFunction str : abc
}

Изменяем строку внутри функции

Точнее меняем содержание строки.

И вот тут начинаются чудеса , сморите внимательно :

Отличие определения uint8_t *str1 = "abc"; от uint8_t str2[]="abc";

void myFunction(uint8_t *str)
{
	printf(" myFunction str : '%s' " ,  str );

	for(uint8_t ii = 0 ; ii < strlen( str ) ; ii++)
		*( uint8_t* )( str + ii ) = '1' ;

	printf("\n");
}

int main(void)
{
	uint8_t *str1 = "abc";
	myFunction( str1 );
	printf(" str1 (x%0.8X)  '%s' \n" , str1 , str1);

	uint8_t str2[]="abcd";
	myFunction( str2 );
	printf(" str2 (x%0.8X)  '%s' \n" , str2 , str2);
}
вывод :

 myFunction str : 'abc' 
 str1 (x0800EE60)  'abc' 
 // почему тут не поменялось содержимое строки

 myFunction str : 'abcd' 
 str2 (x2001FFE0)  '1111
 // а тут поменялось нормально содержимое строки

Обратите внимание на адрес строки в скобочках : в первом случае это (x0800EE60), а во втором (x2001FFE0).

То есть компилятор/компоновщик :

uint8_t *str1 = "abc"; поместил в Flash память контроллера (а она неизменяемая), то есть пытаться записать можно и никто не ругнется, но эффекта не будет.

uint8_t str2[]="abcd"; компилятор поместил в str2 оперативную память (она изменяемая).

Такие нюансы и портят всем жизнь.

В первом случае (чтобы я не делал) ничего не поможет сделать str1 изменяемой ( чтобы он поместил str1 в оперативную память (она же SRAM , или еще точнее в кучу SRAM).
Ни добавление префикса volatile, ни добавление static , ни вынесение всего определения за main, ни объявление static myFunction - ничего не убедит компилятор поместить str1 в оперативную память.

Кардинально вопрос можно решить с помощью функции malloc , но лично я не сторонник в контроллерах пользоваться динамическим выделением памяти от слова вообще.

Да и зачем пользуемся таким вариантом uint8_t str2[]="abcd"; и проблем нет.