함수에서 C 문자열 반환
함수에서 C 문자열을 반환하려고 하는데 작동하지 않습니다.여기 제 코드가 있습니다.
char myFunction()
{
return "My String";
}
»main
이렇게 부르고 있습니다.
int main()
{
printf("%s", myFunction());
}
에도 몇 .myFunction
동작하지 않습니다.예를 들어 다음과 같습니다.
char myFunction()
{
char array[] = "my string";
return array;
}
주의: 포인터는 사용할 수 없습니다!
이 문제에 대한 배경은 거의 없습니다.
몇 월인지 알아내는 기능이 있습니다.예를 들어 1이면 1월 등이 반환됩니다.
할 는 이렇게printf("Month: %s",calculateMonth(month));
는 어떻게 그 것입니다.calculateMonth
★★★★★★ 。
함수 시그니처는 다음과 같아야 합니다.
const char * myFunction()
{
return "my String";
}
배경:
이것은 C&C++에 있어서 매우 중요한 사항이지만, 더 이상 논의할 필요가 없습니다.
C(및 C++)에서 문자열은 0 바이트로 끝나는 바이트 배열일 뿐입니다.따라서 "string-zero"라는 용어는 문자열의 특정 맛을 나타내기 위해 사용됩니다.다른 종류의 문자열이 있지만 C(& C++)에서는 이 맛은 본질적으로 언어 자체에 의해 이해됩니다. 등은 서로 다른 한다."my string"
.
Windows API(C++에 있음)를 사용하는 경우 "LPCTR lpszName"과 같은 함수 파라미터가 매우 정기적으로 표시됩니다.'sz' 부분은 이 'string-zero' 개념을 나타냅니다.즉, 늘(/zero) 터미네이터가 있는 바이트 배열입니다.
설명:
건강한 아기 양육)을 통해 국제적 캐릭터에 대처하는 데 사용됩니다.UTF-8은 mbcs의 예입니다.인트로를 위해서, 나는 조용히 이 모든 것을 '넘긴다'.
메모리:
, " "와 같은 "my string"
9+1(=10!)은 9+1입니다.마지막으로 문자열을 동적으로 할당하는 타이밍을 파악하는 것이 중요합니다.
이 '0 끝'이 없으면 문자열이 없습니다.메모리 내에 일련의 문자(버퍼라고도 함)가 있습니다.
데이터 수명:
이 함수의 사용법은 다음과 같습니다.
const char * myFunction()
{
return "my String";
}
int main()
{
const char* szSomeString = myFunction(); // Fraught with problems
printf("%s", szSomeString);
}
...일반적으로 랜덤으로 처리되지 않은 예외/세그먼트 결함 등이 발생하게 됩니다. 특히 '앞으로' 그렇습니다.
요컨대, 제 답은 맞지만, 10번 중 9번은 그런 식으로 사용하면 프로그램이 다운됩니다.특히 그런 식으로 하는 것이 '좋은 관행'이라고 생각되면 더욱 그렇습니다.요컨대:보통은 그렇지 않아요.
예를 들어, 미래의 어느 시점에서 문자열을 어떤 식으로든 조작할 필요가 있다고 가정해 보겠습니다.일반적으로 코더는 '간단한 경로'를 사용하여 다음과 같이 코드를 작성합니다.
const char * myFunction(const char* name)
{
char szBuffer[255];
snprintf(szBuffer, sizeof(szBuffer), "Hi %s", name);
return szBuffer;
}
컴파일러가 사용하던 szBuffer
printf()
main()
이런 문제는 이 좋습니다.
쉽게 토하지 않는 현을 되돌리는 방법은 두 가지가 있습니다.
- 잠시 존속하는 버퍼(스태틱 또는 다이내믹 할당)를 되돌립니다.에서는, 「classes C++ 의 경우, 「helper classes」)를 사용합니다.
std::string
이나 데이터의 수명(함수의 반환값을 변경해야 함)을 - 정보로 채워진 함수에 버퍼를 전달합니다.
C의 포인터를 사용하지 않고 문자열을 사용하는 것은 불가능하다는 점에 주의해 주십시오.제가 보여드렸듯이, 그들은 동의어입니다.템플릿 클래스가 있는 C++에서도 백그라운드에서 사용되는 버퍼(즉 포인터)는 항상 존재합니다.
그래서 (지금은 수정된) 질문에 더 잘 답하기 위해서.(다양한 '기타 답변'을 제공할 수 있습니다.)
안전한 답변:
예 1: 정적으로 할당된 문자열을 사용합니다.
const char* calculateMonth(int month)
{
static char* months[] = {"Jan", "Feb", "Mar" .... };
static char badFood[] = "Unknown";
if (month < 1 || month > 12)
return badFood; // Choose whatever is appropriate for bad input. Crashing is never appropriate however.
else
return months[month-1];
}
int main()
{
printf("%s", calculateMonth(2)); // Prints "Feb"
}
,, … ...static
does here (많은 프로그래머는 이런 유형의 '정보'를 좋아하지 않는다)는 프로그램의 데이터 세그먼트에 문자열이 들어가는 것입니다.아, 아, 아, 아, 아, 아, 아, 아, 아, 아, 아, 아.
C++로 이행하면, 다음과 같은 전략을 사용할 수 있습니다.
class Foo
{
char _someData[12];
public:
const char* someFunction() const
{ // The final 'const' is to let the compiler know that nothing is changed in the class when this function is called.
return _someData;
}
}
'도움말', '도움말', '도움말', '', '도움말' 같은 을 사용하는 std::string
(다른 사람과 공유하기 위한 라이브러리의 일부가 아닌) 자신의 사용을 위해 코드를 작성하는 경우.
예 2, 발신자 정의 버퍼 사용:
이것은 현을 돌리기 위한 좀 더 '우둔한' 방법이다.반환된 데이터는 발신측 조작의 대상이 아닙니다.즉, 예 1은 발신측으로부터 악용되어 애플리케이션 장애에 노출되기 쉽습니다.이렇게 하면 훨씬 안전합니다(다만 코드 행이 더 많이 사용됨).
void calculateMonth(int month, char* pszMonth, int buffersize)
{
const char* months[] = {"Jan", "Feb", "Mar" .... }; // Allocated dynamically during the function call. (Can be inefficient with a bad compiler)
if (!pszMonth || buffersize<1)
return; // Bad input. Let junk deal with junk data.
if (month<1 || month>12)
{
*pszMonth = '\0'; // Return an 'empty' string
// OR: strncpy(pszMonth, "Bad Month", buffersize-1);
}
else
{
strncpy(pszMonth, months[month-1], buffersize-1);
}
pszMonth[buffersize-1] = '\0'; // Ensure a valid terminating zero! Many people forget this!
}
int main()
{
char month[16]; // 16 bytes allocated here on the stack.
calculateMonth(3, month, sizeof(month));
printf("%s", month); // Prints "Mar"
}
두 번째 방법이 더 나은 이유는 여러 가지가 있습니다.특히 다른 사람이 사용하는 라이브러리를 쓰는 경우(특정 할당/해제 스킴에 잠글 필요가 없으며, 서드파티가 코드를 해제할 필요가 없으며, 특정 메모리 관리 라이브러리에 링크할 필요가 없습니다)는 모두 코드와 마찬가지로 사용자에게 달려 있습니다.e. 그 이유로 대부분의 사람들은 너무 많이 타서 더 이상 그렇게 쓰는 것을 거부하기 전까지 예 1을 선택한다.
면책사항:
나는 몇 년 전에 은퇴했고 지금 내 C는 약간 녹슬었다.이 데모 코드는 모두 C로 올바르게 컴파일 할 필요가 있습니다(단, C++ 컴파일러는 모두 OK).
이 새로운 기능에 주의해 주세요.
const char* myFunction()
{
static char array[] = "my string";
return array;
}
'어레이'를 정적이라고 정의했습니다.그렇지 않으면 기능이 종료되면 변수(및 반환하는 포인터)가 범위를 벗어납니다.그 메모리는 스택에 할당되어 있기 때문에 파손됩니다.이 구현의 단점은 코드가 재진입되지 않고 스레드 세이프가 아니라는 것입니다.
다른 방법으로는 malloc을 사용하여 힙 내의 문자열을 할당하고 코드의 올바른 위치에 해방하는 방법이 있습니다.이 코드는 재진입하여 스레드 세이프가 됩니다.
코멘트에 기재되어 있듯이 공격자가 어플리케이션에 코드를 주입할 수 있기 때문에 이는 매우 나쁜 관행입니다(GDB를 사용하여 코드를 열고 중단점을 만들어 반환된 변수의 값을 오버플로로 수정하고 이제 막 재미를 시작할 필요가 있습니다).
메모리 할당에 대해서는, 발신자가 처리하도록 하는 것이 훨씬 더 좋습니다.다음의 새로운 예를 참조해 주세요.
char* myFunction(char* output_str, size_t max_len)
{
const char *str = "my string";
size_t l = strlen(str);
if (l+1 > max_len) {
return NULL;
}
strcpy(str, str, l);
return input;
}
변경할 수 있는 콘텐츠는 사용자가 변경할 수 있는 콘텐츠뿐입니다.또 다른 부작용 - 적어도 라이브러리의 관점에서 이 코드는 이제 스레드 세이프입니다.이 메서드를 호출하는 프로그래머는 사용된 메모리 섹션이 스레드 세이프인지 확인해야 합니다.
문자입니다.char
의 첫 번째 포인터를 문자 배열의 첫 번째 요소로 반환해야 합니다.수 : ( ) 、 ( if 、 한 if if ( if if if 。 : ( )
함수의 반환 유형에 문제가 있습니다.이 문제는 다음과 같습니다.
char *myFunction()
그러면 당신의 원래 배합이 효과가 있을 거야
C 문자열은 포인터가 포함되지 않으면 사용할 수 없습니다.
한:: 컴컴러러러러경경경경경볼높높높높다다다다..char *
로로 합니다.char
명쾌한 출연진 없이.명시적인 배역 없이.
C 문자열은 문자 배열에 대한 포인터로 정의됩니다.
포인터가 없으면 당연히 문자열을 사용할 수 없습니다.
당신은 있는 메인 함수 호출에, 그리고 이것은메인기능인발신자에 어레이를 작성하고는 호출 수신자, 그 어레이를 착신자에게 건네줄 수 있습니다에 배열을 건네주는 배열을 만들 수 있습니다.myFunction()
.따라서.따라서myFunction
배열 그 실을 채울 수 있다.는 문자열을 배열에 입력할 수 있습니다.그러나 단,신고해야 합니다를 선언할 필요가 있다.myFunction()
as~하듯이
char* myFunction(char * buf, int buf_len){
strncpy(buf, "my string", buf_len);
return buf;
}
그리고 그리고에...main
,myFunction
요.
char array[51];
memset(array, 0, 51); /* All bytes are set to '\0' */
printf("%s", myFunction(array, 50)); /* The buf_len argument is 50, not 51. This is to make sure the string in buf is always null-terminated (array[50] is always '\0') */
그러나 포인터는 여전히 사용됩니다.
.String
로 종단된 ) 유형은 (C' 'Null' 'Null' 'NULL' 'NULL' 'NULL' 'NULL' 'NULL' 'NULL' 'NULL' 'NULL' 'NULL' 입니다).char
그게 당신에게 모든 문제를 야기하고 있어요.대신 다음과 같이 적어야 합니다.
const char* myFunction()
{
return "My String";
}
항상 타입의 을 따는 .const
한편, C의 리터럴로서 포인터에 C의 리터럴을 할당할 수 없습니다.
새롭게 추가된 질문의 배경 스토리를 바탕으로, 그 달의 1에서 12까지의 정수를 반환하고, main() 함수가 스위치문 또는 if-else 래더를 사용하여 인쇄 대상을 결정하도록 하는 것은 어떻습니까?char*라고 하는 것은 결코 최선의 방법은 아니지만, 이러한 수업의 맥락에서 보면 아마 가장 우아한 방법이라고 생각합니다.
아니면 이건 어때?
void print_month(int month)
{
switch (month)
{
case 0:
printf("January");
break;
case 1:
printf("february");
break;
...etc...
}
}
계산한 달을 다른 달이라고 합니다.
A char
1번입니다.문자열도 저장할 수 없고 포인터도 저장할 수 없습니다. 때문에 포인터, 포인터)를 할 수 .char[]
사입입입입다
포인터를 정말로 사용할 수 없는 경우는, 다음과 같은 조작을 실시합니다.
char get_string_char(int index)
{
static char array[] = "my string";
return array[index];
}
int main()
{
for (int i = 0; i < 9; ++i)
printf("%c", get_string_char(i));
printf("\n");
return 0;
}
매직 넘버 9는 끔찍하고, 이것은 좋은 프로그래밍의 예가 아닙니다.하지만 요점은 아시잖아요포인터와 배열은 (일종의) 동일하기 때문에 이것은 약간 부정행위입니다.
함수 프로토타입에는 함수가 문자를 반환한다고 명시되어 있습니다.따라서 함수에서 문자열을 반환할 수 없습니다.
char* myFunction()
{
return "My String";
}
C에서 문자열 리터럴은 정적 상수 메모리 클래스를 가진 배열이므로 이 배열에 포인터를 반환하는 것이 안전합니다.자세한 내용은 C 문자열 리터럴의 스택오버플로우 질문 "Life-time"을 참조하십시오.
함수에서 문자열 반환
#include <stdio.h>
const char* greet() {
return "Hello";
}
int main(void) {
printf("%s", greet());
}
또한 C 함수에서 로컬 변수로 정의된 문자열을 반환할 수 없습니다.함수의 실행이 종료되면 변수가 자동으로 파기(해제)되기 때문입니다.
#include <stdio.h>
#include <stdlib.h>
char *myfunc(){
char *myvar = (char *)malloc(20);
printf("Plese enter some text \n");
fgets(myvar, 20, stdin);
return myvar;
}
int main(){
printf("You entered: %s", myfunc());
}
언급URL : https://stackoverflow.com/questions/1496313/returning-a-c-string-from-a-function
'programing' 카테고리의 다른 글
안드로이드:onIntercept의 차이Touch Event 및 dispatch Touch Event? (0) | 2022.07.02 |
---|---|
Vue 다중 선택이 항상 부트스트랩 입력 그룹 뒤에 표시됨 (0) | 2022.07.02 |
Jackson을 사용하여 JSON 문자열을 Pretty Print JSON 출력으로 변환 (0) | 2022.07.02 |
stdout/stderr 문자열로 리다이렉트 (0) | 2022.07.02 |
2개의 css 스타일파일(rtl, ltr) vue.display 간에 전환하는 방법 (0) | 2022.07.02 |