Use of Malloc in C and pointer member error - 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.

Related

Can someone explain why I'm getting segmentation fault 11?

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.

Dynamically allocating array of strings

I want to dynamically allocate array of strings, but I'm not sure how I can do this. So I thought of making a struct and dynamically allocate that struct. So I made the code below, but this code creates assertion failure.
#include <stdio.h>
#include <stdlib.h>
typedef struct {
char str1[20];
char str2[20];
} String;
int main(void)
{
String * list;
list = (String *)malloc(sizeof(String));
int i = 1;
for (; i < 6; i++) {
realloc(list, i * sizeof(String));
printf("Input String 1: ");
scanf("%s", list[i - 1].str1);
printf("Input String 2: ");
scanf("%s", list[i - 1].str2);
}
for (i = 0; i < 5; i++)
printf("%s\t%s\n", list[i].str1, list[i].str2);
free(list);
}
What have I done wrong and how can I fix this problem?
Thanks :)
The man page for realloc says:
The realloc() function returns a pointer to the newly allocated
memory, which is suitably aligned for any kind of variable and may be
different from ptr, or NULL if the request fails.
The new pointer can be different from the one you passed to realloc, so you need to collect and use the pointer returned by realloc.
A structure always has the same size so with this implementation you'd be stuck with always having an array of size 2.
A way to declare an array of strings (which are themselves arrays of characters) s doing
char **string;
If you want an array of 20 strings then that'd be:
string = malloc(sizeof(char*)*20);
Structs must have constant size, so i don't think the compiler will like you trying to allocate more memory for a structure than what it was defined with.

C structures and pointers

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

malloc always allocate the same address

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);

segmentation fault in C

I am trying to write this code, but it gives me segmentation fault after running the program, could you please help to sort it out?
#include <stdio.h>
#include <string.h>
typedef struct{
int salary;
char* name;
} employee ;
int main(){
employee p[2];
int i;
for(i=0;i<2; i++){
printf("enter sal ");
scanf("%d", &p[i].salary);
printf("enter name ");
scanf("%s", &p[i].name);
}
for(i=0;i<2; i++){
printf("p %d",p[i].salary);
printf("p %s",p[i].name);
}
return 0;
}
You need to allocate memory for the name field: p[i].name = (char*)malloc(MAX_NAME_LEN)
Also, the scanf("%s", &p[i].name) should read scanf("%s", p[i].name).
The structure field name is just a wild character pointer.
char* name;
you are reading the user input as:
scanf("%s", &p[i].name);
into the memory pointed by name which could be anywhere.
To fix this you need to dynamically allocate memory pointed to by name or you can change name to a char array of size one greater than the max length of the name possible.
char name[MAX];
You don't need the & operator when scanf'ing to pointer. And you need to malloc p[i].name
scanf("%s", p[i].name);
You are not allocating memory for char* name. change your data structure to
typedef struct
{
int salary;
char name[50];
}
or allocate memory using malloc
You forgot to allocate memory for p[i].name.
You have to reserve memory for the name member of each instance of employee:
p[i].name = (char*)malloc(expected_max_size);
just before the scanf for that variable. Declaring a pointer to char char* does not assign memory for the actual string pointed to, but just for the pointer itself, and in your example it is not initialized. By using malloc you reserve a piece of memory and makes the pointer point to it. You have to be careful with bounds checking, because you have to reserve the memory beforehand, enough to hold what the user is writing.
You need to allocate memory for the "name" string in your structure. Do this using malloc() or by declaring name as an array of a given size (char name[SIZE]).

Resources