0

Switching to C from Java, and I'm having some troubles grasping memory management

Say I have a function *check_malloc that behaves as such:

// Checks if malloc() succeeds.
void *check_malloc(size_t amount){

  void *tpt;

  /* Allocates a memory block in amount bytes. */
  tpt = malloc( amount );

  /* Checks if it was successful. */
  if ( tpt == NULL ){
      fprintf(stderr, "No memory of %lu bytes\n", amount);
       exit(1); 
  }

  return tpt;
}

I also have the following variables to work with:

FILE *f = fopen("abc.txt", "r");  // Pointer to a file with "mynameisbob" on the first line and 
                                  //                        "123456789"   on the second line 
char *pname;                      // Pointer to a string for storing the name

}

My goal is to use *check_malloc to dynamically allocate memory so that the String pointed to by *pname is just the correct size for storing "mynamisbob", which is the only thing on the first line of the text file.

Here is my (failed) attempt:

int main(int argc, char *argv[]){

FILE *f = fopen("abc.txt", "r");  // A file with "mynameisbob" on the first line and 
                                  //             "123456789"   on the second line 

char *pname;                      // Pointer to a string for storing the name

char currentline[150];            // Char array for storing current line of file

while(!feof(f)){
    fgets(currentline,100,f);
    pname = &currentline; 
}

But I know this probably isn't the way to go about this, because I need to use my nice check_malloc* function.

Additionally, in my actual text file there is a "<" symbol before the name on the first line.But I just want the *pname to point to a String saying "mynameisbob" without the "<" symbol. This isn't that important now, it just is reinforcement to me that I know I can't just set the pointer to point straight to currentline.

Can anyone help me fix my thinking on this one? Thanks a lot.

2 Answers2

0

In C you need to copy chars, not the "strings" (which are just pointers). Check out strcpy() and strlen(). Use strlen() to determine how long the line actually is which fgets has read, then use your malloc() to allocate exactly that (plus 1 for the 0). Then copy the chars over with strcpy().

Peter - Reinstate Monica
  • 15,048
  • 4
  • 37
  • 62
0

There are several problems in your code, see my comments in this example:

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

// Checks if malloc() succeeds.
void *check_malloc (size_t amount) {

  void *tpt;

  /* Allocates a memory block in amount bytes. */
  tpt = malloc( amount );

  /* Checks if it was successful. */
  if (tpt == NULL) {
    fprintf (stderr, "No memory of %lu bytes\n", amount);
    exit (EXIT_FAILURE);
  }

  return tpt;
}

// To avoid subtle errors I have defined buffer size here
#define BUFFER_SIZE 150

// I have used the (void) version of main () here, while not strictly neccessary, you where not using argc and argv anyway, so the can be left out in this case
int main (void) {
  // It might be a good idea to make the filename a char[] as well, but I leave that as an exercise to the reader.
  FILE *f = fopen("abc.txt", "r");  // A file with "mynameisbob" on the first line and
                                    //             "123456789"   on the second line
  // You have to check whether the file was *actually openend*
  if (f == NULL) {
    fprintf (stderr, "Could not open file abc.txt\n"); // '"...%s\n", filename);' might better.
    exit (EXIT_FAILURE);
  }

  char *pname;                      // Pointer to a string for storing the name

  char currentline[BUFFER_SIZE];            // Char array for storing current line of file

  while(!feof (f)) {
        char *res = fgets (currentline, BUFFER_SIZE, f);
        // fgets returns NULL when EOF was encountered before the next '\n'
        if (res) {
          size_t read = strlen (res);
          // The line might have been empty
          if (read) {
            // Better use "sizeof *varname", while char is always 1 byte it is a good practice
            pname = check_malloc ((read + 1) * sizeof *pname); // + 1 because we have to provide an extra char für '\0'
            strncpy (pname, currentline, read); // You have to use strcpy or strncpy to copy the contents of the string rather than just assigning the pointer
            // What was allocated must be freed again
            free (pname);
          }
        }
  }
  fclose(f); // Always close everything you open!
  return EXIT_SUCCESS;
}

Actually you really don't have to use pname in this simple case, because currentline already contains the line, but since you're trying to learn about memory management this should give you a general idea of how things work.

In your code you had this line:

pname = &currentline; 

There are two problems here:

  1. As already mentioned in my code assigning currentline to pname only copies the pointer not the contents.

  2. The correct assignment would be pname = currentline (without the address operator &), because currentline is also a pointer under the hood (it behaves like char *currentline even though it's statically allocated).

Jens Mühlenhoff
  • 14,565
  • 6
  • 56
  • 113