issues with trying to learn malloc - c

When the user enters information for a friend, I want the pointer to allocated appropriate space and the friend information be stored in this allocated space. i've read snippits other places that mention using a buffer array as an argument to scanf, but I'm just having a putting this all together. Here is what I have so far.
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <conio.h>
//Structure for contacts
typedef struct friends_contact{
char *First_Name;
char *Last_Name;
char *home;
char *cell;
}fr;
void menu(fr*friends ,int* counter,int user_entry,int i);
void setFirst(fr*,int *,int i);
char getFirst(fr*,int i);
void add_contact(fr*friends,int* counter,int i);
void print_contact(fr*friends ,int* counter, int i);
int main()
{
int user_entry=0;
fr friends[5];
int buffer[50];
int counter=0;
int i=0;
for(i=0;i<5;i++)
{
friends[i].First_Name = (char*) malloc(sizeof(char) * 64);
free(friends[i].First_Name);
}
menu(friends, &counter,user_entry,i);
getch();
return 0;
}
//Menu function
void menu(fr*friends,int* counter,int user_entry, int i)
{
do{
int result;
printf("\nPhone Book Application\n");
printf("1) Add friend\n2) Delete friend\n3) Show a friend\n4)"
"Showonebook\n5)Exit\n");
scanf("%d", &user_entry);
if(user_entry==1)
{
add_contact(friends,counter,i);
}
if(user_entry==2)
{
}
if(user_entry==3)
{
}
if(user_entry==4)
{
print_contact(friends, counter,i);
}
}while(user_entry!=5);
}
void setFirst(fr*friends, int* counter, int i)
{
//malloc issue **
friends=(fr*) malloc(sizeof(fr));
printf("Enter a first name \n");
scanf("%s",friends[*counter].First_Name);
}
char getFirst(fr*friends , int pos)
{
printf("%s ", friends[pos].First_Name);
return *friends[pos].First_Name;
}
void add_contact(fr*friends,int* counter,int i)
{
setFirst(friends,counter,i);
(*counter)++;
}
void print_contact(fr*friends ,int* counter, int i)
{
for( i = 0; i < *counter; i++)
if (strlen(friends[i].First_Name))
{
getFirst(friends, i);
}
}
This is only part of the code obviously, and as of right now I get a segmentation fault after I enter a name into the add name function. It loops to the menu one last time before quitting. I realize that I have gone wrong somewhere, and I would like to try and fix this with the buffer solution. Solutions anyone?

Your fr variable is a pointer to some location on the stack that's already got space allocated. You shouldn't be using that - it's already initialized and you can't malloc it (or at least you never ever should). You should instead pass a pointer and initialize it.
That is to say:
fr *friends;
And then when you want to allocate space
friends = (fr*) malloc(sizeof(fr)* NUMBER OF FR YOU WANT);
Furthermore, you need to initialize the elements of your structure if you want to use them, since they're all pointers. This would be done similarly
friends[i].First_Name = (char*) malloc(sizeof(char)* (LENGTH OF STRING + 1));
Or it would be friends[i]->First_Name depending on how you've sent it along to your function.
A good solution for you would just be to initialize the members of the struct inide your main
int i;
fr friends[5];
for(i=0;i<5;i++)
{
friends[i].First_Name = (char*) malloc(sizeof(char) * 64);
friends[i].Last_Name = (char*) malloc(sizeof(char) * 64);
friends[i].home = (char*) malloc(sizeof(char) * 64);
friends[i].cell = (char*) malloc(sizeof(char) * 64);
}
//
//Do functions (without malloc'ing)
//
for(i=0;i<5;i++)
{
free(friends[i].First_Name);
free(friends[i].Last_Name);
free(friends[i].home);
free(friends[i].cell);
}
Here I've chosen 64 to be the length of string. You can set it to whatever you think works.
The bottom line is that you have to allocate space for a pointer before you can use it. Otherwise it's not pointing to any memory you can use and you'll get a segmentation fault. Also, don't forget to free once you're done with the memory you've allocated. Do remember that you can't use it once you've freed it (unless you malloc it again).

Related

How to properly use realloc in c? [duplicate]

This question already has answers here:
How can I create a dynamically sized array of structs?
(10 answers)
Closed 4 years ago.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <stdbool.h>
#define LENGHT 20
typedef struct {
unsigned id;
char name[LENGHT];
char genre[LENGHT];
char nazionality [LENGHT];
int year_carrier_started;
bool check;
}Artist;
void print(Artist *arr, int *i);
void addOne(Artist *arr, int *i);
int main(void) {
int index = 5;
Artist *array = malloc(sizeof(int)*index);
for (int i=0;i<index;i++)
{
printf("Insert a number:\n");
scanf("%d",&array[i].id);
}
do
{
addOne(array,&index);
print(array,&index);
}while(1);
system("pause");
free(array);
return EXIT_SUCCESS;
}
void addOne(Artist *arr, int *i)
{
realloc(arr,sizeof(Artist)*(*i)+1);
printf("Insert another one:\n");
scanf("%d",&arr[*i].id);
*i = *i +1;
print(arr,i);
}
void print(Artist *arr, int *i)
{
for (int j=0;j<*i;j++)
{
printf("Number: %d position %d\n",arr[j].id,j);
}
}
Hi guys, I got this struct from a piece of my program, what I need to is to realloc everytime the user wants to add a new Artist. After adding like 10/15 more users, it crashes for no reason (at least for me there is not). What am I doing wrong? (Dat *i is passed by reference, it counts how many artists are there already).
How to properly use realloc in c(?)
After adding like 10/15 more users, it crashes for no reason
#Christian Gibbons well advises: use the return value of realloc(). The former value of array may not be valid.
Multiply the right values
// sizeof(Artist)*(*i)+1
sizeof(Artist)*((*i)+1)
Use the return value of realloc()
// realloc(array,sizeof(Artist)*(*i)+1);
void *new_ptr = realloc(array,....
Check realloc() results
// realloc(array,sizeof(Artist)*(*i)+1);
void *new_ptr = realloc(array,....
if (new_ptr == NULL) OutOfMemory();
else array = new_ptr;
Consider sizing by the object than the type
// realloc(array,sizeof(Artist)*(*i)+1);
void *new_ptr = realloc(array, sizeof *array *((*i)+1));
All together
Artist *array = malloc(sizeof *array);
if (array == NULL) Handle_OutOfMemory();
...
void *new_ptr = realloc(array, sizeof *array * ((*i)+ 1));
if (new_ptr == NULL) {
// `array` still has *i elements assigned to it.
Handle_OutOfMemory();
} else {
array = new_ptr;
(*i)++;
}
realloc will attempt to resize your allocated memory in place if it can, but if there's not enough room to expand to the new size where it is, it will have to move the data to a new location. Realloc returns a pointer to the location for this reason. You should also test to make sure that it did not err. So something like this:
Artist *arr = malloc(sizeof(*arr) * i);
Artist *temp = realloc(arr, sizeof(Artist)*((*i)+1) // Borrowing this from Yunnosch
if(temp) {
arr = temp;
}
else {
free(arr);
// more error handling
}

segmentation fault using malloc

I'm new to C, so this may be a silly question to ask:
What I want to do here is to input the data to the array of pointers to a structure and then print it out. But I get a segmentation fault when running into the insert function.
Below is my code
common.h
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
typedef struct book * Book;
struct book{
int id;
char *name;
};
extern int b_insert(Book *b, int id, char *name);
extern int b_print(Book books[], int len);
insert.c
#include "common.h"
int b_insert(Book *b, int id, char *name){
Book p;
p = (Book)malloc(sizeof(struct book));
p->id = id;
strcpy(p->name, name);
*b = p;
printf("success insert book:\n");
printf("\tID: %d Name: %s\n", (*b)->id, (*b)->name);
return 0;
}
int b_print(Book books[], int len){
int i;
printf("Book List\n");
for(i=0; i<len; i++){
printf("books[%d] = ID: %d, Name: %s\n", i, books[i]->id, books[i]->name);
}
return 0;
}
main.c
#include "common.h"
#define MAX 2
int main(){
Book books[MAX];
Book *b=books;
int i;
int id;
char name[10];
for(i=0; i<MAX; i++){
printf("please input new books info\n");
printf("ID: ");
scanf("%d", &id);
printf("Name: ");
scanf("%s", name);
if(b_insert(b, id, name) == -1){
printf("fail to insert\n");
}
b++;
}
b_print(books, MAX);
return 0;
}
Main problem:
Allocate memory for p->name before using
strcpy(p->name, name);
using malloc:
p->name = malloc(10); //Or some other size
Other problems:
Remove the cast here:
p = (Book)malloc(sizeof(struct book));
Why? Here is the answer
if(b_insert(b, id, name) == -1){ will never be true.
Check the result of malloc to check if it was successful in allocating memory.
Check the return value of all the scanfs to see if it was successful in scanning data.
Add a length modifier to the second scanf to prevent buffer overflows:
scanf("%9s", name); /* +1 for the NUL-terminator */
You're not allocating space for name:
int b_insert(Book *b, int id, char *name){
Book p;
p = malloc(sizeof(struct book));
if (p != NULL)
{
p->name = malloc(strlen(name)+1); // It allocates space where the input name will be copied.
if (p->name != NULL)
{
p->id = id;
strcpy(p->name, name);
*b = p;
printf("success insert book:\n");
printf("\tID: %d Name: %s\n", (*b)->id, (*b)->name);
}
else return -1; // No space to allocate string
}
else return -1; // No space to allocate struct
return 0;
}
As mentioned before, allocate space for p->name. You should probably also use something different to read the book title, either scanf format %ms with a pointer to a char pointer, or %9s with your buffer, otherwise the title "war or peace" will also result in a segfault.
Here you create a static variable and the space for it is allocated automatically.
Book p;
You can allocate a space manually when you assign it to pointer, in this line it's not pointer but static variable.
p = (Book)malloc(sizeof(struct book));
What's more if you want to refer to attribute of static variable you should use "." instead of "->". So you have two option. Create a pointer and allocate a space for the structure and then you "->" oraz create static variable.
p->id = id;

Strange segmentation default

The problem I want to solve is: Count the number of occurrences of key words in a C code. Here's the code:
The problem is that I get a segmentation fault. In my code I mentioned where
is the problem. Can you, please, explain me why ?
In header:
struct Chei
{
char *cuv;
int contor;
};
typedef struct Chei chei;
int ReadCode(char *a[]);
void determine(chei *Ch, char *temp, int size);
void Frequency(chei *Ch, int nr_lines, char *a[], int size);
In main:
chei tab_chei[] = {{"while", 0},{"if", 0}, {"case", 0}, {"switch", 0}};
int size = sizeof(tab_chei)/sizeof(tab_chei[0]);
char *Code[MaxL];
int nr_lines;
nr_lines = ReadCode(Code);//number of lines of text
Frequency(tab_chei, nr_lines, Code, size);
In function file:
I think there is no problem with reading text (function ReadCode() -- here I allocated memory for each Code[i] using malloc). I used an array of pointers to char for this.
// This functions determines if the word "temp" is a keyword, and increases
//"contor" if it is.
void determine(chei *Ch, char *temp, int size)
{
int i;
for (i = 0; i < size; ++i)
{
if (!strcmp(Ch[i].cuv, temp))
{
Ch[i].contor++;
break;
}
}
}
Array "a" contains the text.
void Frequency(chei *Ch, int nr_lines, char *a[], int size)
{
int i;
char temp[MaxCh];
char *token = 0;
strcpy(temp, a[0]);//I put a[0] as a particular case
token = strtok(temp, " ");
determine(Ch, token, size);
while (token != NULL)
{
token = strtok(NULL, " ");
determine(ch, token, size); //here is the problem.
//I observed that if I delete this line, there is no error
//but still it isn't what I want to get
}
for (i = 0; i < size; ++i)
{
printf("\n%-10s%-4d", Ch[i].cuv, Ch[i].contor);
}
}
token = strtok(NULL, " ");
determine(ch, token, size); //here is the problem.
You're not checking token before passing it to determine(). The strcmp() call is undefined behaviour when given a null pointer.
I think the problem is that you did not allocate memory for each of the string the pointer will point to, char *Code[MaxL];.
you only allocated memory for the pointers, you need to do something like
Code[0] = calloc(0, 100);
.

How to sort strings with this code? I am failing at basics

I am trying to sort city names inputted. The code below seems correct to me, but while it does compile successfully, it does not work as I expected.
Am I failing in understanding pointers? Let me correct if below are true:
names type is a char **
names[0] type is char *
If I want to swap strings after checking if they are bigger with strcmp(), I have to change the values inside names[i] and names[j] because the values inside these values are pointers to actual city names. When these are interchanged, they point to each others' char array and I am done.
If my 3rd idea is true, I have to pass parameters to swap function as char * because swap function will take names[i] and names[j] as parameters and the type of these are char *.
The thinking was like above while writing the code below. But it seems I am failing at my logic because code does not work as intended.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int i,j;
char *temp;
void swap(char *, char *);
int main(void){
char *names[4];
//gets city names
puts("Enter 4 city names:");
for (i = 0; i < 4; i++)
{
names[i]=malloc(100);
fgets(names[i],99,stdin);
}
//bubble sort names array and swap if necessary
for (i = 0; i < 3; i++)
{
for (j = i+1; j<4 ; j++)
{
if (strcmp (names[i],names[j]) >0 )
{
swap(names[i], names[j]);
}
}
}
puts("Printing sorted array");
for (i = 0; i < 4; i++)
{
printf("%s", names[i]);
}
getch();
}
void swap(char *first, char *second){
temp=first;
first=second;
second=temp;
}
You need to pass a pointer to the pointer:
void swap(char **first, char **second)
{
char *temp = *first;
*first = *second;
*second = temp;
}
As it was you are only modifying the copy of the pointer, not the original. We use pointers to look at the original...hence you need a pointer to a pointer; you are modifying a pointer!!
To get your head round it, I'd recommend swapping your pointers to strings for ints and sort those instead. If it was ints you were sorting your swap function would look like this:
void swap(int first, int second) // These ints/parameters have been copied
{
first = second; // This only modifies the local copy
// etc..
}
To modify the original values you would need to use a pointer:
void swap(int *first, int *second)
{
*first = *second;
// etc...
}
Your swap function has no effect at all at the passed pointers, you need to change it like this, so that the passed pointers are modified:
swap(&names[i], &names[j]);
void swap(char **first, char **second)
{
temp=*first;
*first=*second;
*second=temp;
}
Your swap function has no effect. Because I feel it is not obvious for you, let's try with a simpler example.
If you wanted to swap two integers, your function would take int instead of char*. Your function would be (I have just replaced the char* by int):
void swap(int first, int second){
int temp=first;
first=second;
second=temp;
}
When you call swap(a, b) with a and b 2 int variables, their values are copied into first in second. Then you swap the contain of the variables first and second. The important point is that you don't change the original variables a and b.
The correct function would be:
void swap(int *first, int *second){
int temp=*first;
*first=*second;
*second=temp;
}
Because that way, you pass the address of the variables and you modify the original variables this way. If it is not clear, you should document yourself about what is a pointer and how it works.
Now, you can change back the int by a char*:
void swap(char **first, char **second){
char* temp=*first;
*first=*second;
*second=temp;
}
Your swap function is incorrect, you can't assign strings like that. You need something like this (non-optimal)
void swap(char *a, char *b) {
char tmp[256];
strcpy(tmp, a);
strcpy(a, b);
strcpy(b, tmp);
}
Your problem is not with pointers, but with function calls. When you pass a value to a function, and modify that value, the "source" of the value is not necessarily changed.
void swap(char **first, char **second) {
char *temp;
temp=*first;
*first=*second;
*second=temp;
}
swap(&names[i], &names[j]);
Or you could do it like this:
void swap(char **arr, int x, int y) {
char *temp;
temp = arr[x];
arr[x] = arr[y];
arr[y] = temp;
}
swap(names, i, j);
In the first case you pass to the function the two addresses, the contents of which are to be changed. In the second you pass the master array address, and the two locations.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int i,j;
char *temp;
void swap(char **, char **);
int main(void){
char *names[4];
//gets city names
puts("Enter 4 city names:");
for (i = 0; i < 4; i++)
{
names[i]=malloc(100);
fgets(names[i],99,stdin);
}
//bubble sort names array and swap if necessary
for (i = 0; i < 3; i++)
{
for (j = i+1; j<4 ; j++)
{
if (strcmp (names[i],names[j]) >0 )
{
swap(&names[i], &names[j]);
}
}
}
puts("Printing sorted array");
for (i = 0; i < 4; i++)
{
printf("%s", names[i]);
}
}
void swap(char **first, char **second){
temp=*first;
*first=*second;
*second=temp;
}

Segfault in my csv_loader() function

I'm trying to write a csv parser in C, but every time I get a segfault in this function. I don't know how to fix it.
char*** csv_loader(char *filename){
FILE* file_xx;
file_xx = fopen(filename, "r");
if(file_xx==NULL){
printf("Failed to open File, no such file or directory!\n");
return 0;
}
int c_=0;
int **linenumbers;
int l=lines(filename);
linenumbers=malloc(sizeof(int)*l);
char*** loaded_csv;
int counter_line=0;
int counter_row=0;
loaded_csv=malloc(sizeof(char **) *l);
loaded_csv[0][0]=malloc(getfirstcolumn(filename)*sizeof(char)+2);
if(NULL==loaded_csv){
printf("Failed to initialize 'char** loaded_csv'!\n");
return 0;
}
int c_c=0;
int *cm=get_column_map(filename);
for(c_c=0;c_c<l;c_c++){
loaded_csv[c_c]=malloc(sizeof(char *)*cm[c_c]);
}
while(c_!=EOF){
c_=getc(file_xx);
if(c_=='\n'){
linenumbers[counter_line][cm[counter_line]]=counter_row+2;
loaded_csv[counter_line][cm[counter_line]]=malloc(counter_row*sizeof(char));
if(NULL == loaded_csv[counter_line][cm[counter_line]]){
return 0;
}
loaded_csv[counter_line][counter_row]='\0';
counter_row=0;
counter_line++;
}else{
if(c_==','){
counter_row=0;
}else{
counter_row++;
}
}
}
fclose(file_xx);
FILE*fgetsread;
fgetsread=fopen(filename, "r");
int ident, ident_c;
for(ident=0;ident<l;ident++){
for(ident_c=0;ident_c<cm[ident];ident_c++){
fgets(loaded_csv[ident][ident_c], linenumbers[ident][ident_c], fgetsread);
loaded_csv[ident][ident_c][linenumbers[ident][ident_c]-2]='\0';
}
}
fclose(fgetsread);
free(linenumbers);
return loaded_csv;
}
The Debugger says it's this line:
loaded_csv[0][0]=malloc(getfirstcolumn(filename)*sizeof(char)+2);
Does anyone know what's the bug? I'm yet new to C and anyway try to understand the malloc thing...
PS: the other functions are here: http://pastebin.com/VQZ4d5UU
So, you've allocated space on the line right before:
loaded_csv=malloc(sizeof(char **) *l);
That is fine and dandy, but loaded_csv[0] isn't yet initialized to somewhere you own. So, when you do the following line
loaded_csv[0][0]=malloc(getfirstcolumn(filename)*sizeof(char)+2);
you are trying to set a variable located in some random location (wherever loaded_csv[0] happens to be right then).
If you want to touch loaded_csv[0][0], you'll have to make sure that loaded_csv[0] is pointing to valid memory first (probably by allocating memory for it via malloc before you allocate something for loaded_csv[0][0].)
You've got a problem with this line:
loaded_csv[0][0]=malloc(getfirstcolumn(filename)*sizeof(char)+2);
Which suggest you are not allocating and initializing loaded_csv[0][0] right.
Here is an example of how to initialize and use a char ***var:
#include <windows.h>
#include <ansi_c.h>
char *** Create3D(int p, int c, int r);
int main(void)
{
char ***pppVar;
pppVar = Create3D(10,10,10);
//test pppVar;
strcpy(pppVar[0][0], "asdfasf");
strcpy(pppVar[0][1], "the ball");
return 0;
}
char *** Create3D(int p, int c, int r)
{
char *space;
char ***arr;
int x,y;
space = calloc (p*c*r*sizeof(char),sizeof(char));
arr = calloc(p * sizeof(char **), sizeof(char));
for(x = 0; x < p; x++)
{
arr[x] = calloc(c * sizeof(char *),sizeof(char));
for(y = 0; y < c; y++)
{
arr[x][y] = ((char *)space + (x*(c*r) + y*r));
}
}
return arr;
}
Be sure to keep track of and free(x) appropriately.

Resources