0

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

1
  • Updated my answer regarding your segmentation fault. Commented Jan 7, 2011 at 14:52

6 Answers 6

3
  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 )
Sign up to request clarification or add additional context in comments.

3 Comments

Please read above question been edited about segmentation fault error
After the read() please add: files[i].name[namelen] = '\0'; - you will get a segfault when issuing strlen() on memory that doesn't have a '\0' (because strlen only stops counting when it reaches a \0).
Also, change read( file, files[i].name, namelen ) - you're trying to write on top of a pointer when you should be writing to the memory the pointer points to (I think you need to re-read K&R on pointers and the & operator).
2

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.

2 Comments

Please read above question been edited about segmentation fault error I get as result
Two problems 1) Read into files[i].name, not &files[i].name 2) you are missing the trailing NULL byte in the string --files[i].name[namelen] = 0; should fix that.
1

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.

1 Comment

Hm, interesting trick, but I suspect that you'd need identical usage patterns for all allocations, or a flag in the structure, indicating if it is a "free all" or "free strings, then free base" (probably from a custom wrapper around free).
1

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.

Comments

0

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.

Comments

0
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.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.