c++ - 为什么这个程序会崩溃
大家讲道理
大家讲道理 2017-04-17 11:10:58
0
3
588
void GetMemory(char *p)
{
    p = (char *)malloc(100);
}
void Test(void) 
{
    char *str = NULL;
    GetMemory(str);   
    strcpy(str, "hello world");
    printf(str);
}
大家讲道理
大家讲道理

光阴似箭催人老,日月如移越少年。

reply all(3)
Ty80

The questioner seems not to know much about C language. It is recommended to read basic tutorials such as "K & R".

Variable assignment error (cause of crash)

You are trying to point GetMemory() to a memory allocated by *str via malloc().

However, function parameters in C language are passed by value. The value *str of NULL is copied to *p, and then *p is pointed to the value returned by malloc(). At this time, GetMomory() The function ends. The value of *str remains NULL, nothing has changed. After that, you use strcpy to try to copy "hello world" to NULL, but of course something goes wrong.

The correct approach is to pass the address of the pointer variable *str to GetMemory(char **p). *str itself is a pointer, pointing to an address. Although *str is a pointer, a pointer also has its own address. Pass the address of *str to **p, and **p will be a pointer to the pointer.

At this point, your main problem has been solved. You can skip the rest and look directly at the code .

Omission free()

After the program exits, the operating system will automatically release all memory. However, it is never wrong to release memory immediately after using it.

printf() Usage error

Also, your usage of printf() is wrong. The parameters of printf() cannot directly be the data to be printed. A literal string with a conversion specifier is required, and the following parameters are the actual parameters to be formatted.

Some people say that according to the prototype of printf(), there is no problem in directly following a string printf(str). However, str can lead to serious security issues if the content is obtained externally, such as user input. Both GCC and Clang will issue warnings about such usage.

For example, on old 32-bit Linux:

#include <stdio.h>

int main(int argc, char **argv)
{
    char *secret = "This is a secret!\n";
    printf(argv[1]);
    return 0;
}

If compiled using -mpreferred-stack-boundary=2

$ gcc -mpreferred-stack-boundary=2 FormatString.c -o FormatString
$ ./FormatString %s
This is a secret!

Oh? why is that? I don’t know much about the bottom layer, I can only say that this is related to the memory out of bounds of varargs, and *secret happens to be at this memory address. Have you ever thought of the "Heartbleed" vulnerability that was exposed in OpenSSL some time ago?

-mpreferred-stack-boundary=2 is not a necessary means of attack. Given the right conditions and careful calculation, the harm could be much greater than this.

Therefore such usage must be prohibited and

should be used
printf("%s\n", str);

or

puts(str);

No #include any header files

Before using the library function, you need to #include provide the header file of the corresponding function.

  • printf() Powered by stdio.h
  • malloc() Powered by stdlib.h
  • strcpy() Powered by string.h

There is no main() function

main() The function is the entrance of the program. Without the entrance, where would the program be executed?


The corrected procedure is as follows.

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

void GetMemory(char **p)
{
    *p = (char *)malloc(100);
}

void Test(void) 
{
    char *str = NULL;
    GetMemory(&str);   
    strcpy(str, "hello world");
    printf("%s\n", str);

    free(str);
    *str = NULL; // 避免误用已悬空的指针
}

int main(void)
{
    Test();
    return 0;
}
Peter_Zhu

Damn it... you don't support posting codes in the answer comments, so I'll add another answer. Some comments on the best answer

  1. The prototype of printf is
int printf ( const char * format, ... );

Therefore, printf(str) is feasible.

However, if str is content entered by the user or obtained externally, str may contain malicious code, which can be used to carry out memory overflow and execute arbitrary code attacks. Therefore, doing so should be strictly prohibited. ——Biergaizi

  1. C/C is a good habit to initialize the applied memory space, so making a memset or initializing the first unit to zero is a practice worth encouraging
  2. In addition, as mentioned above, remember to free the malloc memory, otherwise there will be no memory available for use after a while. Also remember to clear the pointer after free. Avoid calling this free pointer by mistake after the code is too long
  3. Strings in c must end with 0. The strcpy you use here does this for you when copying strings. But you have to be aware of it.
  4. Your GetMemory can directly return a pointer, eliminating the problem of passing pointers to pointers
char* GetMemory()
{
   char* p = (char *)malloc(100);
   memset(p, 0, SIZE); // or *p = 0;
   return p;
}

The following code is compiled on win7 and runs successfully

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define SIZE 100
void GetMemory(char **p)
{
   *p = (char *)malloc(
   memset(*p, 0, SIZE); // or **p = 0;
}

void Test(void) 
{
    char *str = NULL;
    GetMemory(&str);   
    strcpy(str, "hello world");
    printf(str);
    free( str);
    str = NULL;
}

int main(void)
{
    Test();
    return 0;
}
黄舟

The simplest answer is that the poster didn’t understand: Pass by reference and pass by value

If you want to modify the content pointed to by str, you have to pass the pointer to str

Latest Downloads
More>
Web Effects
Website Source Code
Website Materials
Front End Template