Here is my code:
int main() {
typedef struct {
int recordCount;
char *firstName;
char *secondName;
char *id;
char *email;
}student;
student *students = malloc(sizeof(*students));
int i = 0;
while (students[i].firstName[0] != '.'){
students[i].firstName = (char *)malloc(sizeof(char*));
scanf("%s", students[i].firstName);
i++;
students = realloc(students, sizeof(students) * (i + 1));
}
}
When I run it through a for loop it works, I'm pretty sure it's just something silly going on with my while loop.
malloc returns a block of uninitialized memory. So students[i].firstName is an uninitialized pointer which you attempt to dereference. Reading and dereferencing an uninitialized pointer invokes undefined behavior, which in this case manifests as a crash.
When you do allocate space for the firstName member, you only allocate sizeof(char*) bytes for it which is the size of a pointer, not necessarily the length of a string you would want to read.
Create a buffer to read strings into that's big enough for what you might need, then use strdup to create a copy to assign to the relevant pointer.
student *students = NULL;
int i = 0;
char str[100];
scanf("%99s", str);
while (str[0] != '.'){
students = realloc(students, sizeof(*students) * (i+1));
students[i].firstName = strdup(str);
i++;
scanf("%99s", str);
}
For a start,
students[i].firstName = (char *)malloc(sizeof(char*));
allocates enough space for a character pointer, typically four or eight bytes.
While there are some names that will fit in that (such as Pax or Bob), the vast majority probably won't.
You need to allocate enough space for the largest name (and string terminator), such as with:
#define MAX_NAME_LEN 100
students[i].firstName = malloc(MAX_NAME_LEN + 1);
There are plenty of issues in your code.
When you are using malloc, you actually specify the data type and not the pointer type which is I believe is not your intent here. If you are specifying a pointer type with sizeof, the pointer will point to a memory location having the size of the pointer. This is not what you want in this case.
After the line student *students = malloc ... . The students will point to a memory location which will hold zero values in firstName. You need to use malloc for these. Since you are not doing this you are getting a segmentation fault because you are dereferencing an invalid pointer (pointing to location 0). You are trying to access it first and using malloc afterwards.
If you
student *students = malloc(sizeof(*students));
you are allocating size of one pointer. What you want to do is instead
student *students = malloc(sizeof(students));
and for the same reason, students[i].firstName = (char *)malloc(sizeof(char*)) quite surely do not have enough memory for your name as well, try malloc(sizeof(char)*100) or so.
Related
I am working on a short program that reads a .txt file. Intially, I was playing around in main function, and I had gotten to my code to work just fine. Later, I decided to abstract it to a function. Now, I cannot seem to get my code to work, and I have been hung up on this problem for quite some time.
I think my biggest issue is that I don't really understand what is going on at a memory/hardware level. I understand that a pointer simply holds a memory address, and a pointer to a pointer simply holds a memory address to an another memory address, a short breadcrumb trail to what we really want.
Yet, now that I am introducing malloc() to expand the amount of memory allocated, I seem to lose sight of whats going on. In fact, I am not really sure how to think of memory at all anymore.
So, a char takes up a single byte, correct?
If I understand correctly, then by a char* takes up a single byte of memory?
If we were to have a:
char* str = "hello"
Would it be say safe to assume that it takes up 6 bytes of memory (including the null character)?
And, if we wanted to allocate memory for some "size" unknown at compile time, then we would need to dynamically allocate memory.
int size = determine_size();
char* str = NULL;
str = (char*)malloc(size * sizeof(char));
Is this syntactically correct so far?
Now, if you would judge my interpretation. We are telling the compiler that we need "size" number of contiguous memory reserved for chars. If size was equal to 10, then str* would point to the first address of 10 memory addresses, correct?
Now, if we could go one step further.
int size = determine_size();
char* str = NULL;
file_read("filename.txt", size, &str);
This is where my feet start to leave the ground. My interpretation is that file_read() looks something like this:
int file_read(char* filename, int size, char** buffer) {
// Set up FILE stream
// Allocate memory to buffer
buffer = malloc(size * sizeof(char));
// Add characters to buffer
int i = 0;
char c;
while((c=fgetc(file))!=EOF){
*(buffer + i) = (char)c;
i++;
}
Adding the characters to the buffer and allocating the memory is what is I cannot seem to wrap my head around.
If **buffer is pointing to *str which is equal to null, then how do I allocate memory to *str and add characters to it?
I understand that this is lengthy, but I appreciate the time you all are taking to read this! Let me know if I can clarify anything.
EDIT:
Whoa, my code is working now, thanks so much!
Although, I don't know why this works:
*((*buffer) + i) = (char)c;
So, a char takes up a single byte, correct?
Yes.
If I understand correctly, by default a char* takes up a single byte of memory.
Your wording is somewhat ambiguous. A char takes up a single byte of memory. A char * can point to one char, i.e. one byte of memory, or a char array, i.e. multiple bytes of memory.
The pointer itself takes up more than a single byte. The exact value is implementation-defined, usually 4 bytes (32bit) or 8 bytes (64bit). You can check the exact value with printf( "%zd\n", sizeof char * ).
If we were to have a char* str = "hello", would it be say safe to assume that it takes up 6 bytes of memory (including the null character)?
Yes.
And, if we wanted to allocate memory for some "size" unknown at compile time, then we would need to dynamically allocate memory.
int size = determine_size();
char* str = NULL;
str = (char*)malloc(size * sizeof(char));
Is this syntactically correct so far?
Do not cast the result of malloc. And sizeof char is by definition always 1.
If size was equal to 10, then str* would point to the first address of 10 memory addresses, correct?
Yes. Well, almost. str* makes no sense, and it's 10 chars, not 10 memory addresses. But str would point to the first of the 10 chars, yes.
Now, if we could go one step further.
int size = determine_size();
char* str = NULL;
file_read("filename.txt", size, &str);
This is where my feet start to leave the ground. My interpretation is that file_read() looks something like this:
int file_read(char* filename, int size, char** buffer) {
// Set up FILE stream
// Allocate memory to buffer
buffer = malloc(size * sizeof(char));
No. You would write *buffer = malloc( size );. The idea is that the memory you are allocating inside the function can be addressed by the caller of the function. So the pointer provided by the caller -- str, which is NULL at the point of the call -- needs to be changed. That is why the caller passes the address of str, so you can write the pointer returned by malloc() to that address. After your function returns, the caller's str will no longer be NULL, but contain the address returned by malloc().
buffer is the address of str, passed to the function by value. Allocating to buffer would only change that (local) pointer value.
Allocating to *buffer, on the other hand, is the same as allocating to str. The caller will "see" the change to str after your file_read() returns.
Although, I don't know why this works: *((*buffer) + i) = (char)c;
buffer is the address of str.
*buffer is, basically, the same as str -- a pointer to char (array).
(*buffer) + i) is pointer arithmetic -- the pointer *buffer plus i means a pointer to the ith element of the array.
*((*buffer) + i) is dereferencing that pointer to the ith element -- a single char.
to which you are then assigning (char)c.
A simpler expression doing the same thing would be:
(*buffer)[i] = (char)c;
with char **buffer, buffer stands for the pointer to the pointer to the char, *buffer accesses the pointer to a char, and **buffer accesses the char value itself.
To pass back a pointer to a new array of chars, write *buffer = malloc(size).
To write values into the char array, write *((*buffer) + i) = c, or (probably simpler) (*buffer)[i] = c
See the following snippet demonstrating what's going on:
void generate0to9(char** buffer) {
*buffer = malloc(11); // *buffer dereferences the pointer to the pointer buffer one time, i.e. it writes a (new) pointer value into the address passed in by `buffer`
for (int i=0;i<=9;i++) {
//*((*buffer)+i) = '0' + i;
(*buffer)[i] = '0' + i;
}
(*buffer)[10]='\0';
}
int main(void) {
char *b = NULL;
generate0to9(&b); // pass a pointer to the pointer b, such that the pointer`s value can be changed in the function
printf("b: %s\n", b);
free(b);
return 0;
}
Output:
0123456789
This is my struct:
typedef struct Person {
char* name;
int age;
float height;
float weight;
char** hobbies;
}person;
I tried to fill the name but it just ain't working.
void main(){
person Asaf;
char buffer[50];
int length;
puts("Please enter the name of the student");
gets(buffer);
length = strlen(buffer);
Asaf.name = realloc(buffer, length);
}
I just can't figure the problem...
I guess it has something to do with the realloc function.
please help!! :P
You are trying to realloc (which operates on the heap) an array that is allocated on the stack, which is a no-no. What you want instead is something like:
Asaf.name = strdup(buffer); /* POSIX: allocates a string copy of buffer on the heap */
Or, more standardly:
Asaf.name = (char*) malloc(strlen(buffer) + 1); /* TODO: should check allocations for NULL return */
strcpy(Asaf.name, buffer);
Also, you should use fgets() rather than gets(). gets() is inherently dangerous and should never be used because it doesn't do any bounds checking on the array to which it writes.
fgets(buffer, sizeof(buffer), stdin);
This function returns a pointer to the newly allocated memory, or NULL if the request fails.
so as realloc operates on heap here getting pointer to the memory allocation in heap area to a pointer guy sitting in stack can cause some problems buddy.
so maybe undefined behavior can be the answer for the output you are getting.
About how using realloc, all the didactic examples include this-
Use realloc:
1>Check if it's NULL.In this case use perror and exit the program
2>If it's not NULL use the memory allocated
3>Free the memory when you don't need it anymore.
possible duplicate of:How to use realloc in a function in C
#include <stdio.h>
#include <stdlib.h>
struct Album {
char* title;
}
int main(){
int i, size;
struct Album* pAlbum;
printf("Enter the number of album: ");
scanf_s("%d", &size);
pAlbum = malloc(sizeof(pAlbum) * size);
for(i=0; i<size; i++) {
printf("Enter the album title: ");
scanf_s("%p", pAlbum[i].title);
}
free(pAlbum);
return 0;
}
I want to let the user enter the title for as many albums as they want. The error is that scanf only comes up once for pAlbump[i].tittle for the loop. I'm i allocating the memory incorrectly?
pAlbum = malloc(sizeof(pAlbum) * size);
This allocates size pointers. But you wish to allocate size structs.
Your allocation should therefore be
pAlbum = malloc(sizeof(*pAlbum) * size);
or
pAlbum = malloc(sizeof(struct Album) * size);
or
pAlbum = calloc(size, sizeof(struct Album));
Once you've dealt with that, you will need to allocate memory to store each string in the struct. That's going to need separate calls to malloc.
for(i=0; i<size; i++) {
printf("Enter the album title: ");
pAlbum[i].title = malloc(...); // you need to decide how much to allocate
scanf_s("%s", pAlbum[i].title); // hmm, this simply begs a buffer overrun ...
}
And then you'd need to free each of the title strings that you allocated in that loop before freeing the array of structs.
Before using data member title of the structure in statement
scanf_s("%p", pAlbum[i].title);
you have to allocate memory that will be pointed to by this data member and where you are going to store entered data.
And you have to use tag struct before name Album in statement
pAlbum = malloc(sizeof( struct pAlbum) * size);
And instead type specifier "%p" you have to use %s that to enter a string.
First, if you are not to add extra members to your structure then just pull out the char* to the outside and use it. If you want the type to be called Album, you could write typedef char *Album;. You are allocating memory to hold pointers to strings but not the memory that holds the actual strings. Your scanf uses the wrong format %p, use %s to read a string of characters; the scanf is reading to an unallocated piece of memory so that's going to cause a runtime error.
To allocate memory for n items, use calloc (for contiguous allocate). calloc allocates a block of memory for an array of n elements, each of them elem_sizebytes long.
calloc(n, elem_size);
You should know how many bytes each title is or use a maximum number of bytes in your code. There exists a function that will take care of the memory allocation for you but it's not part of the standard. It's called strdup.
You have two options, either make title member an array of fixed size
struct Album {
char title[100];
}
and use scanf_s this way
scanf_s("%99s", pAlbum[i].title, _countof(pAlbum[i].title));
Or, use malloc
char tmp[100];
if (scanf_s("%99s", tmp, _countof(tmp)) == 1)
pAlbum[i].title = strdup(tmp);
Also, to allocate size structs, do as David Heffernan said.
I must do this:
Write the function void AddName(char *Names[], int *size) that takes an array of strings Names and a pointer of integer size.
Checks if there is still enough space to store a new name.
If there is, asks the user to input his name and store it in a huge array of char (100 char).
Calculate the length of his name.
Allocate a dynamic memory to store his name and store its location in one of Names
indexes.
Increment the size by one.
I have wrote this code but malloc always allocate the same address so the whole array Names become similar
int const MAX = 3;
void AddName(char *Names[],int *size)
{
int tempsize = *size;
char *s;
if (tempsize > MAX)
printf("\n ERROR: Array is full. Cannot add.");
else
{
int i,len=0;
char name[100];
printf("Enter the name: ");
scanf("%s",name);
for(i=0; name[i]!='\0'; i++)
len++;
s = (char *)malloc((len+1)*sizeof(char));
s = &name;
Names[*size]=s;
*size=*size+1;
printf("\n Done.\n");
}
}
After you allocate your memory, you store the address into the variable s.
Then you overwrite that value with the address of your name variable.
As a result, you will never know the allocated address, because you discarded it with the overwriting.
s = &name;
This is wrong. You are obliterating the address that malloc just returned to you. What you want is to copy the contents of name to the memory position s. For that you need strncpy. Replace s = &name with:
strncpy(s, name, len);
Or, since you know that strlen(name) == len, and that you allocated enough memory, you can just use strcpy():
strcpy(s, name);
I am new to C and learning structs. I am trying to malloc a char pointer with size 30 but it is giving a segmentation fault(core dump). I searched it on the internet & SO but am not able to resolve this. Any help will be much appreciated.
Probably I am accessing the char* member of the struct incorrectly ?
typedef struct{
int x;
int y;
char *f;
char *l;
}str;
void create_mall();
void create_mall() //Malloc the struct
{
str *p;
p->f = (char*)malloc(sizeof(char)*30); // segmentation fault here
p->l = (char*)malloc(sizeof(char)*30);
printf("Enter the user ID:");
scanf("%d",&p->x);
printf("\nEnter the phone number:");
scanf("%d",&p->y);
printf("\nEnter the First name:");
scanf("%29s",p->f);
printf("\nEnter the Last name:");
scanf("%29s",p->l);
printf("\nEntered values are: %d %d %s %s\n",p->x,p->y,p->f,p->l);
}
int main(void)
{
create_mall();
return 0;
}
Here's your problem:
str *p;
You've declared a pointer to an instance of str, but you haven't initialized it with a value. You either need to move this variable to the stack:
str p;
...or malloc some memory for it first:
str *p = (str*)malloc(sizeof(str));
You never allocated space for the struct itself, only a pointer to it.
Try something like:
str *p = malloc(sizeof(str));
As many people have pointed out, you need to allocate memory for that str struct, before writing the fields of it.
The best way to do so in C is:
p = malloc(sizeof *p);
This has the following advantages:
No cast, since no cast is needed in C and having a cast can hide actual errors.
No duplication of type information, by using the sizeof operator to compute how much storage is needed for the value p points at.
When you then allocate the string space, you can simplify it to:
p->f = malloc(30);
Because:
No cast, for the very same reason.
C guarantees that sizeof (char) is always 1, so using it like you did adds nothing, 1 * 30 is always just 30.
Last, you should always check the return value of malloc() before using it, since it can fail and return NULL.
Check for NULL values in return of malloc() function.
Also str *p; < is not initialised.
initialize p as str *p = malloc(sizeof(str));
The problem lies here.
str *p; ---> Problem Line 1<br>
p->f = (char*)malloc(sizeof(char)*30); ----> Problem Line2
p->l = (char*)malloc(sizeof(char)*30);
You have declared a pointer p of type str.
Problem 1:
You have not initialized this pointer to NULL. Thus, p can point to anything.
Problem 2:
Since p is an uninitialized pointer, p->f can point anywhere which is causing the segfault.
Below is the correct way
str *p = NULL;
p = malloc(sizeof(str));
// Check p for NULL
memset(p, 0, sizeof(str));
Now you have an initialized memory pointed by p. You are now free to use it as you want.