Understanding pointers in a structure and malloc

2019-08-29 07:36发布

问题:

I am just learning C (reading Sam's Teach Yourself C in 24 hours). I've gotten through pointers and memory allocation, but now I'm wondering about them inside a structure.

I wrote the little program below to play around, but I'm not sure if it is OK or not. Compiled on a Linux system with gcc with the -Wall flag compiled with nothing amiss, but I'm not sure that is 100% trustworthy.

Is it ok to change the allocation size of a pointer as I have done below or am I possibly stepping on adjacent memory? I did a little before/after variable in the structure to try to check this, but don't know if that works and if structure elements are stored contiguously in memory (I'm guessing so since a pointer to a structure can be passed to a function and the structure manipulated via the pointer location). Also, how can I access the contents of the pointer location and iterate through it so I can make sure nothing got overwritten if it is contiguous? I guess one thing I'm asking is how can I debug messing with memory this way to know it isn't breaking anything?

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

struct hello {
    char *before;
    char *message;
    char *after;
};

int main (){
    struct hello there= {
        "Before",
        "Hello",
        "After",
    };
    printf("%ld\n", strlen(there.message));
    printf("%s\n", there.message);
    printf("%d\n", sizeof(there));
    there.message = malloc(20 * sizeof(char));
    there.message = "Hello, there!";
    printf("%ld\n", strlen(there.message));
    printf("%s\n", there.message);
    printf("%s %s\n", there.before, there.after);
    printf("%d\n", sizeof(there));
    return 0;
}

I'm thinking something is not right because the size of my there didn't change.kj

Kind regards,

回答1:

Not really ok, you have a memory leak, you could use valgrind to detect it at runtime (on Linux).

You are coding:

there.message = malloc(20 * sizeof(char));
there.message = "Hello, there!";

The first assignment call malloc(3). First, when calling malloc you should always test if it fails. But indeed it usually succeeds. So better code at least:

there.message = malloc(20 * sizeof(char));
if (!there.message) 
  { perror("malloc of 20 failed"); exit (EXIT_FAILURE); }

The second assignment put the address of the constant literal string "Hello, there!" into the same pointer there.message, and you have lost the first value. You probably want to copy that constant string

strncpy (there.message, "Hello, there!", 20*sizeof(char));

(you could use just strcpy(3) but beware of buffer overflows)

You could get a fresh copy (in heap) of some string using strdup(3) (and GNU libc has also asprintf(3) ...)

there.message = strdup("Hello, There");
if (!there.message) 
  { perror("strdup failed"); exit (EXIT_FAILURE); };

At last, it is good taste to free at program end the heap memory. (But the operating system would supress the process space at _exit(2) time.

Read more about C programming, memory management, garbage collection. Perhaps consider using Boehm's conservative GC

A C pointer is just a memory address zone. Applications need to know their size.

PS. manual memory management in C is tricky, even for seasoned veteran programmers.



回答2:

there.message = "Hello, there!" does not copy the string into the buffer. It sets the pointer to a new (generally static) buffer holding the string "Hello, there!". Thus, the code as written has a memory leak (allocated memory that never gets freed until the program exits).

But, yes, the malloc is fine in its own right. You'd generally use a strncpy, sprintf, or similar function to copy content into the buffer thus allocated.



回答3:

Is it ok to change the allocation size of a pointer [...] ?

Huh? What do you mean by "changing the allocation size of a pointer"? Currently all your code does is leaking the 20 bytes you malloc()ated by assigning a different address to the pointer.