programing

함수에서 C 문자열 반환

goodcopy 2022. 7. 2. 22:19
반응형

함수에서 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()이런 문제좋습니다.

쉽게 토하지 않는 현을 되돌리는 방법은 두 가지가 있습니다.

  1. 잠시 존속하는 버퍼(스태틱 또는 다이내믹 할당)를 되돌립니다.에서는, 「classes C++ 의 경우, 「helper classes」)를 사용합니다.std::string이나 데이터의 수명(함수의 반환값을 변경해야 함)을
  2. 정보로 채워진 함수에 버퍼를 전달합니다.

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"
}

,, … ...staticdoes 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 char1번입니다.문자열도 저장할 수 없고 포인터도 저장할 수 없습니다. 때문에 포인터, 포인터)를 할 수 .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

반응형