c char * question

2019-05-05 04:00发布

This is an absolutly noob question, but I don't seem to find an appropiate answer anywhere so here it goes, given this code:

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

void initialize( char * buffer)
{
    buffer = malloc(1);
    *buffer='a';
}


int main(void) {
    char * buff;
    buff = malloc(sizeof(char));
    *buff = 'b';
    initialize(buff);
    puts("Contents of buffer are: ");
    puts(buff);
    return 0;
}

The output of main is always 'b', which is really weird to me. I thought that by passing a pointer to initialize I could modify the value of the pointer declared in main, but for some reason it seems to be passing the variable by value, and when returning I have the values specified in main, thus 'b'.

I would like to know why is this...should I pass a reference to a pointer instead? something like char *& ??

Regards, Alex

标签: c char
6条回答
Explosion°爆炸
2楼-- · 2019-05-05 04:09

You need to modify your initialize() function to take a pointer to your buffer and pass in the address of the pointer. Although it receives the buffer you pass in, you cannot change what buff is pointing to that way. Just be aware that you will have a memory leak in this case and you cannot print the contents as a string as it isn't properly null terminated.

void initialize(char **buffer)
{
    *buffer = malloc(sizeof(char));
    **buffer='a';
}

int main(void) {
    char *buff;
    buff = malloc(sizeof(char));
    *buff = 'b';
    initialize(&buff);
    puts("Contents of buffer are: ");
    printf("%c\n", *buff);
    return 0;
}

Answers to the comments below:

I don't get why a need a pointer to a pointer still...is this like a reference in C++?

When I read your code, I thought that you wanted to change what the buff variable (in main()) was pointing to, a new buffer. I thought that when I saw that you were allocating a new buffer in your initialize() function. To be able to change a value of a variable from a different location (or function), you'd need the address to that variable. Since it was originally a character pointer char *, you would have needed a pointer to that character pointer, char **. And yes, this is like a reference in C++, only more verbose.

So I can modify the value of the passed variable?

If you had intended to just modify the contents of the buffer that was passed in, Krtek covers that. All you needed to do was leave out the new allocation of the buffer and modify what the buffer was pointing to.

void initialize(char *buffer)
{
    /* *buffer = malloc(sizeof(char)); */ /* do not need this */
    /* modify the buffer that was passed in */
    *buffer='a';
}

Regarding the memory leak problem

Actually, the memory leak was caused by allocating a new buffer while not freeing the previously allocated memory. You effectively had this:

char *buff = malloc(sizeof(char)); /* allocate some memory */
buff = malloc(sizeof(char));       /* oops, memory leak */

you mean using puts with a non-null terminated string? Is this why you are using printf("%c\n", *buff)? forcing the string to end with \n?

This was a different issue here. puts() takes a null-terminated string and prints it to standard output followed by a new line. It wouldn't be a memory leak to print potentially garbage text, it's just... something else. Your buffer only contained space for a single character (without the null-terminator). You therefore shouldn't use puts() to print the contents of the buffer. You should only be printing that single character. The use of printf() with the '\n' was to end up with the same output behavior as puts().

查看更多
做自己的国王
3楼-- · 2019-05-05 04:13

You modified the copy of your pointer to point in another place, but your real pointer doesn't point to it. If you wan't your code to work use this function.

void initialize( char ** buffer)
{
    *buffer = malloc(1);
    **buffer='a';
}

then call initialize(&buff);

查看更多
Juvenile、少年°
4楼-- · 2019-05-05 04:21

When you do this

buffer = malloc(1);

The buffer variable passed originally from main is unaffected as it has been passed by value.

If you write this:

void initialize( char **buffer)
{
    *buffer = malloc(1);
    **buffer='a';
}

Then you will see the change.

Edit1: You need to understand * operator. buffer is a pointer in itself. *buffer is actually the location pointed to by buffer and changing it doesn't affect buffer actually.

查看更多
做自己的国王
5楼-- · 2019-05-05 04:22

The first thing you do in your function it to reassign another place in the memory to buffer with a new malloc. Then you modify this new memory location, but buff in the main function isn't modified, since it's still pointing on the old location.

If you remove the malloc, it will work :

void initialize( char * buffer) {
    *buffer='a';
}

Now we are modifying the initial memory location.

查看更多
ゆ 、 Hurt°
6楼-- · 2019-05-05 04:24
void initialize( char * buffer)
{

    // buffer is a local pointer to this function which will have 
    // same value as buff in main AT THIS POINT.

    // now you call malloc to allocate memory and make buffer
    // point to that memory. So the value of buffer got changed now.
    // buff in main remains unchanges.
    buffer = malloc(1);

    // now you write to the memory allocated.
    *buffer='a';

    // key point is buff in main is still pointing where it was.
}


int main(void) {

    // buff is now a wild pointer.
    char * buff;

    // now you allocate memory using malloc and make buff point to that memory.
    buff = malloc(sizeof(char));

    // you write to the memory pointed to by buff.
    *buff = 'b';

    // you pass buff BY VALUE to the function initilize.
    initialize(buff);

    // since a copy of buff (buffer) was changed, buff still points
    // to a memory that has b in it.
    puts("Contents of buffer are: ");
    puts(buff);
    return 0;
}

If you want the called function to affect the value of buff you need to pass its address:

void initialize( char ** buffer)
{
    *buffer = malloc(1);
    **buffer='a';
}

and call it as:

initialize(&buff);

but note that this will leak the memory allocated in main. Since you've already allocated memory in main you can just remove the malloc:

void initialize( char * buffer)
{
    *buffer='a';
}
查看更多
戒情不戒烟
7楼-- · 2019-05-05 04:32

In case a bug-free snippet without memory leaks is preferred, here are some alternatives to what has already been posted, more applicable to programming in the real world.

Note that the same "code module" that mallocs should also free. Do not malloc in one module and free in another, that is very bad practice!

Version 1:

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

void set (char* buffer)
{
    *buffer='a';
}


int main (void)
{
    char* buff;

    buff = malloc(sizeof(char));  /* main allocates */
    *buff = 'b';

    set (buff);

    puts("Contents of buffer are: ");
    printf("%c", *buff);  /* don't use puts on single characters! */

    free(buff); /* main cleans up its own mess */
    return 0;
}

Version 2:

/* main.c */
#include <stdio.h>
#include <stdlib.h>
#include "my_functions.h"


int main (void)
{
    char * buff;

    buff = malloc(sizeof(char));
    *buff = 'b';

    alloc_and_set (&buff);

    puts("Contents of buffer are: ");
    printf("%c", *buff);

    cleanup();
    return 0;
}

my_functions.h

#ifndef MY_FUNCTIONS_H
#define MY_FUNCTIONS_H

void alloc_and_set (char** buffer);
void cleanup (void);

#endif /* MY_FUNCTIONS_H */

my_functions.c

#include "my_functions.h"

static char* internal_buffer = NULL;  /* used to keep track of allocated data */

void alloc_and_set (char** buffer)
{
  if(internal_buffer == NULL)  /* make function memory leak proof */
  {
    internal_buffer = malloc(sizeof(char));
  }

  *internal_buffer = 'a';
  *buffer = internal_buffer;
}

void cleanup (void)
{
    free(internal_buffer);   /* my_functions module cleans up its own mess */
    internal_buffer = NULL;
}
查看更多
登录 后发表回答