daza166
daza166

Reputation: 3693

c programming malloc question

Just got query regarding c malloc() function. I am read()ing x number of bytes from a file to get lenght of filename, like ' read(file, &namelen, sizeof(unsigned char)); ' .

The variable namelen is a type unsigned char and was written into file as that type (1 byte). Now namelen has the lenght of filename ie namelen=8 if file name was 'data.txt', plus extra /0 at end, that working fine.

Now I have a structure recording file info, ie filename, filelenght, content size etc.

   struct fileinfo
        {
              char *name;
              ...... other variable like size etc

        };
struct fileinfo *files;

Question: I want to make that files.name variable the size of namelen ie 8 so I can successfully write the filename into it, like ' files[i].name = malloc(namelen) '

However, I dont want it to be malloc(sizeof(namelen)) as that would make it file.name[1] as the size of its type unsigned char. I want it to be the value thats stored inside variable &namelen ie 8 so file.name[8] so data.txt can be read() from file as 8 bytes and written straight into file.name[8?

Is there a way to do this my current code is this and returns 4 not 8

files[i].name = malloc(namelen);
//strlen(files[i].name) - returns 4

//perhaps something like
malloc(sizeof(&namelen)) but does not work

Thanks for any suggestions

Have tried suggested suggestions guys, but I now get a segmentation fault error using:

printf("\nsizeofnamelen=%x\n",namelen); //gives 8 for data.txt
files[i].name = malloc(namelen + 1);
read(file, &files[i].name, namelen);
int len=strlen(files[i].name); printf("\nnamelen=%d",len);
printf("\nname=%s\n",files[i].name);  

When I try to open() file with that files[i].name variable it wont open so the data does not appear to be getting written inside the read() &files[i].name and strlen() causes segemntation error as well as trying to print the filename

Upvotes: 0

Views: 1864

Answers (6)

DanielV
DanielV

Reputation: 663

read(file, &files[i].name, namelen);

should be

read(file, files[i].name, namelen);

Because files[i].name stores the address of the allocated buffer. Since the prototype for read is void* your compiler might be letting you get away with passing a char** rather than reporting an error.

Also as maxschlepzig said, don't forget to add a \0 to the end of the buffer.

Upvotes: 0

maxschlepzig
maxschlepzig

Reputation: 39047

malloc returns uninitialized memory, thus the result of

strlen(files[i].name)

directly after

files[i].name = malloc(namelen);

is undefined.

And strlen counts the characters until the first '\0' character in a memory block - it does not return the memory block size allocated by a former malloc call.

Regarding question update:

A read does not terminate the destination with a '\0' character, and this is why you get a segmentation fault.

Inserting a

files[i].name[namelen] = '\0';

properly terminates the C-string and should fix this issue.

Alternatively you could use calloc instead of malloc.

Upvotes: 1

tperk
tperk

Reputation: 91

Did you allocate space for the files? Currently, it is struct fileinfo * files;

Assuming you did something like this: files = malloc(sizeof(struct fileinfo) * num_files);

printf("\nsizeofnamelen=%x\n",namelen); //gives 8 for data.txt
files[i].name = malloc(namelen + 1);
read(file, &files[i].name, namelen);
files[i].name[namelen] = '\0'; // NUL-terminate the string.
int len=strlen(files[i].name); printf("\nnamelen=%d",len);
printf("\nname=%s\n",files[i].name);  

If you don't NUL-terminate the string (file[i].name) then you will keep reading random stuff and possibly segfault.

Upvotes: 0

unwind
unwind

Reputation: 399703

If the filename won't change, you can be a bit efficient and allocate both the structure and the space for the filename in the same malloc():

struct fileinfo *files = malloc(sizeof *files + namelen + 1);
files->name = (char *) (files + 1);

This allocates a single block of memory which is large enough for the struct fileinfo (i.e. sizeof *files bytes) and the '\0'-terminated filename (namelen + 1). The second line make the name member of the struct point at the first byte after the struct itself.

You can then go ahead and write the filename into files->name by e.g. loading it with another call to read().

You can free the entire structure, including the filename, with a single call to free(files) when you're done with it.

Upvotes: 1

Lukáš Lalinský
Lukáš Lalinský

Reputation: 41306

The code you have is (almost) the correct way to allocate the memory, you need to include space for the trailing NULL byte:

files[i].name = malloc(namelen + 1);

Note that at this point the string is not initialized, so strlen(files[i].name) will either return a random number of crash. You can use memset() to zero the memory and then strlen(files[i].name) will return 0. If you read the data from the file, strlen(files[i].name) will return 8.

Upvotes: 2

PP.
PP.

Reputation: 10864

  1. a string is strlen(name) + 1 bytes long (because of the terminating \0).
  2. if namelen = strlen("data.txt") (i.e. 8) then you must allocate files[i].name = malloc(namelen + 1)
  3. any memory you allocate using malloc() is undefined. You cannot perform strlen() on memory you just allocated - you must set the memory you've allocated first
  4. only after you allocate the memory can you use the memory, i.e. strncpy( files[i].name, "data.txt", namelen + 1 ) and only then can you strlen( files[i].name )

Upvotes: 3

Related Questions