I'm just starting on the road the learning C, and ran into some difficulty:
The code listed below is giving me the following error:
Attaching to program: `/workfolder/cocoa/c_stuff/bookshelf/build/Debug/bookshelf', process 1674.
Cannot access memory at address 0xa0df194
Cannot access memory at address 0xa0df194
// code start
#define MAX_NAME_LENGTH 200
#define MAX_AUTHOR_LENGTH 200
#define MAX_DESCRIPTION_LENGTH 1000
#define MAX_PUBLISHER 200
#define MAX_ISBN 50
//structures<
typedef struct {
char title[MAX_NAME_LENGTH];
char author[MAX_AUTHOR_LENGTH];
char ISBN[MAX_ISBN];
char description[MAX_DESCRIPTION_LENGTH];
char publisher[MAX_PUBLISHER];
} Book;
void getUserInput(Book *s[])
{
printf("what is the book's title ?\n");
fgets(s[book_count]->title, MAX_NAME_LENGTH, stdin);
printf("what is the author's name?\n");
fgets(s[book_count]->author, MAX_AUTHOR_LENGTH, stdin);
printf("what is the ISBN?\n");
fgets(s[book_count]->ISBN, MAX_ISBN, stdin);
printf("write a short description\n");
fgets(s[book_count]->description, MAX_DESCRIPTION_LENGTH, stdin);
printf("what is the book's publisher\n");
fgets(s[book_count]->publisher, MAX_PUBLISHER, stdin);
printf("want to add another book ? Y\\N\n");
book_count++;
if(tolower(fgetc(stdin)) == 'y')
{
return getUserInput(s);
}
else
{
return;
}
}
int main (int argc, const char * argv[]) {
// insert code here...
Book *book_shelf[100];
if((book_shelf[0] = (Book *)malloc(sizeof(Book))) == NULL)
{
exit(1);
}
getUserInput(book_shelf);
return 0;
}
The code compiles properly, and the function runs fine the first time (all the questions get asked and the struct receives the data); but when the user types 'y' to add another book, the mem error occurs.
Any ideas where the error is happening?
Thanks in advance!
You've only ever allocated memory for the first book in main - after that it tries to write to the next slot in the array, which doesn't point to an allocated block of memory, giving you a seg-fault. You're going to have to allocate memory for each book you want to read in.
In addition, since C doesn't know how long an array is, you have to pass that information along into function calls. (And I don't see where you're defining book_count.)
You might try something along these lines:
void getUserInput(Book *s[], int *book_count, int max_book_count)
{
if (book_count == max_book_count) return; // If we've filled all the slots, we can't add anymore without causing trouble.
s[book_count] = malloc(sizeof(Book));
..
if(tolower(fgetc(stdin)) == 'y')
{
(*book_count)++;
getUserInput(s, book_count, max_book_count);
}
return;
}
int main (int argc, const char * argv[]) {
// insert code here...
Book *book_shelf[100];
int book_count = 0;
getUserInput(book_shelf, &book_count, 100);
// Make sure to free all the malloc'd data
}
Even better in this situation, would just be using a loop and skipping the whole recursion step.
int main (int argc, const char * argv[]) {
// insert code here...
Book *book_shelf[100];
char response = 'y';
int book_count = 0;
while (book_count < 100 && response == 'y')
{
book_shelf = malloc(sizeof(Book));
response = getUserInput(book_shelf[book_count++]);
}
// make sure to free all the allocated data!
}
char getUserInput(Book *book)
{
// write input straight to book
printf("what is the book's title ?\n");
fgets(book->title, MAX_NAME_LENGTH, stdin);
...
return tolower(fgetc(stdin));
}
Unless I'm reading something wrong, you haven't defined book_count before using it as an array subscript.
Within main, you allocated on the stack an array of 100 pointers to the Book Structure. I believe it was your intent to allocate 100 structures and then pass the address to that block of structures to getUserInput
Change main to:
Book book_shelf[100];
...
getUserInput(book_shelf);
...
EDIT: OOPS Missed the single Book malloc mentioned in the earlier post. That ones Correct for the first book. If you edit as above and eliminate the
if (book_shelf[0]...) check, you'll accomplish your intended results
You allocate just space for the firstbook, not for the others (malloc in main)
I guess there is some code missing, no declaration and initialization of book_count
You should use loops instead of recursion
Use not recursion but loops for this kind of repetition
Recursion is probably overkill for this problem where a simple do { ... } while(user keeps answering yes) would do. However the problem you having is in main with your Book *book_shelf[100]. There are several ways you could solve this problem.
First change it to an array of Book's like samills suggests:
Book book_shelf[100];
and then change your getUserInput to something like this:
getUserInput(Book *book_shelf, int offset, int length) {
if(offset < 0 || offset >= length) {
return;
}
//...
return getUserInput(book_shelf, offset + 1, length)
}
Or you could use your existing code and change you getUserInput function to look something like this and remove the malloc from main:
getUserInput(Book *book_shelf) {
book_shelf[book_count] = (Book*)malloc(sizeof(Book));
// ...
}
props for correct use of the sizeof operator (I see that thing misused so often it makes my eyes bleed).
As in Josh's answer, by adding the following lines to your code should make it work:
book_count++;
if(tolower(fgetc(stdin)) == 'y')
{
if((book_shelf[book_count] = (Book *)malloc(sizeof(Book))) == NULL)
{
printf("Cannot allocate memory for Book");
exit(1);
}
return getUserInput(s);
}
else
{
return;
}
However, I encourage you not to use the recursive function for getting input. Recursive can lead to difficulties in debugging. You may consider using normal loop instead.
Note: I'm assuming the book_count is global variable which has been initialized to 0
thanks a lot for the replies!
I realized that I hadn't malloc-ed enough memory to handle more then one element of the struct array (Exactly what Josh is saying). So essentially:
Book *book_shelf;
if(book_shelf = (Book*)malloc(sizeof(Book)) == NULL)//exit code
so the second time around I would hit a memory issue.
thanks again!
Looks like your still doing it wrong:
Book *book_shelf;
if(book_shelf = (Book*)malloc(sizeof(Book)) == NULL)//exit code
book_shelf is only the size of a pointer. When you do the malloc you only allocate one Book at a time. This is wrong. You need to allocate contiguous memory for an array of Book objects all in one instanciation of an array.
Like
Book book_shelf[100];
not
Book *book_shelf[100];
or using malloc, use your pointer to point to an array instanciated using
100*malloc(sizeof(Book)).
You may get lucky that no other heap memory is allocated in between your malloc(sizeof(Book)) calls and that the memory management system is alocating contiguous memory by default. Also, book_shelf will only point to the last malloced Book structure, not the first one as you indicated you want in your original question.
Josh is also not allocating enough memory at one time. Use a linked list if you want to keep extending elements to the end of your book_shelf one-by-one.
factorial with pointer and recursion
#include<iostream.h>
#include<conio.h>
int show(int *p)
{
int f;
int x=*p;
if(*p==1) //boundry checking for recursion
return 1;
else
f=x*show(&(--*p)); //this code is similar to f=x*show(n-1); with non-pointers
return f;
}
void main()
{
int a=6;
int b=show(&a);
cout<<b;
getch();
}
Related
I made a simple base converter and the very first thing it does is it gets a string from the user. I wanted the string to be dynamic, so I did this:
char *getStr() {
char *str = NULL;
/*LOOP THAT USES getc() TO SAVE CHARS INTO THE STRING AND GROWS IT USING realloc() IF NEEDED*/
return str;
}
int main() {
char *str;
str = getStr();
//SOME STUFF HAPPENS HERE WITH THE str. IT REMAINS THE SAME LENGTH.
free(str) //IS THIS THE RIGHT PLACE TO FREE IT?
}
So, is free() in the right place here? I understand that since both str pointers point to the same address it should work, right? Also, by the way, how does free() know where to stop deallocating, when it only has the first address?
This may be pretty obvious, but I wanna make sure.
In your example, this is the right place for it.
The simplest free are called when you are just no need for the data anymore.
The tricky part in my experience is when things don't go as planned, or when your program can exit with multiple ways.
Take a look at this dummy program that has absolutely no real purpose.
A program that takes an integer, if this integer has a value superior to 10, the program will add 1 to it. If not, it will exit the whole program with exit (1)
static void add_one_to_num(int *num)
{
if (*num < 10)
{
free(num);
exit(1);
}
*num = *num + 1;
}
int main()
{
int *num;
num = malloc(sizeof(int));
printf("Enter a number higher than 10: ");
scanf("%d", num);
add_one_to_num(num);
printf("num: %d\n", *num);
free(num);
return (0);
}
In this program, we might exit at the function add_one_to_num so you need to free that pointer in that place.
By writing more and more programs you will get the hang of it, because it's actually very logical and not at all chaotic (It could be a pain in the neck for large programs to track down all allocated memories throughout all the functions the pointers are passed to ).
just make sure to free when you longer need the data, or when something changes the natural flow of your program.
Here is the code:
#include <stdio.h>
#include <stdlib.h>
#define numOfStrings 10
#define sizeOfString 30
void crashControl();
int main()
{
char **strArray = (char **)malloc(numOfStrings*sizeof(char *));
crashControl(strArray);
for (int i = 0; i < numOfStrings; i++)
{
strArray[i] = (char *)malloc(sizeOfString*sizeof(char));
crashControl(strArray[i]);
}
return 0;
}
void crashControl(char *A)
{
if (!A)
{
printf("Not enough space.\n");
exit(1);
}
}
It seems work correctly. When I increase numOfStrings too much crashControl(strArray) works correctly. Likewise when I increase sizeofString too much crashControl(strArray[i]) works correctly as well. But I wonder, am I doing right or wrong? Is there a risk or a bug for this code? The parameter of crashControl() function has one dimensional array, am I free to use this function for any N-dimensional array?
Yes, you may use it for multidimensional arrays. However, it could be good to rewrite it in that case. Instead of taking a char * as argument you should take a void * to make it general.
What your function is testing is basically nothing more than if the pointer is a null pointer or not. Nothing more, nothing less. I'd say it is pretty bad designed since that function gives the impression that it does more. I cannot see any reason to do a null check in a separate function. It is better to just do the check immediately after malloc, like this:
char **strArray = (char **)malloc(numOfStrings*sizeof(char *));
if(!strArray) {
printf("Error allocating memory\n");
exit(1);
}
If you really want to do this check in a function I would suggest naming it isNull and write it like this:
int isNull(void * ptr)
{
if(ptr)
return 0;
else
return 1;
}
but since this function always would be called within an if statement it is pretty pointless.
I have a struct typedef to SmartArray that has a variable char **array. I have been trying to debug the code for several hours, and have made lots of progress. However, i'm stuck on this particular bug. I have a function to print said array out. It will print twice, and then on the third time it does not print at all! I have a feeling this has something to do with how I am adding malloc to an array being one one does not print out correct. For the last section of the array, it prints "Testing Na". Any ideas? I would appreciate the help.
Here is the part of the function I am suspecting is the cause, however, I can't seem to find it: //allocate min space for string
printf("approaching malloc\n");
strPtr = malloc( sizeof(char) * (strlen(str) + 1) );
if(strPtr == NULL)
{
return NULL;
}
printf("made it past malloc!\n");
strcpy(strPtr, str);
//if crash probably this code
smarty->array[index] = strPtr;
if(smarty->array[0] == NULL)
{
return NULL;
}
return strPtr;
Here is my test code:
typedef struct SmartArray
{
// We will store an array of strings (i.e., an array of char arrays)
char **array;
// Size of array (i.e., number of elements that have been added to the array)
int size;
// Length of the array (i.e., the array's current maximum capacity)
int capacity;
} SmartArray;
int main(void)
{
int i; char buffer[32];
SmartArray *smarty1 = createSmartArray(-1);
printf("Array created\n");
// Print the contents of smarty1.
printf("\n-- SMART ARRAY 1: --\n");
printSmartArray(smarty1);
printf("Made it past print!\n");
put(smarty1,"Hi, my name is ");
put(smarty1, "Hello, my name is");
put(smarty1, "Testing Names");
printf("made it past put!\n");
printf("smart away is now\n");
printSmartArray(smarty1);
printf("end of main!\n");
I feel like it's something completely obvious I'm just overlooking because I am a novice.
Here's a picture of what i'm trying to get it to look like in memory:
click here for memory diagram
UPDATE: I figured out why it wasn't printing all the names, but the program segfaults atfter the print function.
I think it is because you are trying to extend your array using malloc. A C array can only point to one block of storage at a time. When you use malloc it will allocate an entirely new block of storage and you are trying to add that on to the end of your array when you write smarty->array[index] = strPtr.
If you want to extend the size of your C array, use realloc instead which will allocate a new, bigger block of memory for your array and copy the existing content to it as well.
If that doesn't solve the problem can you post your entire put function?
i try to store name and age in a dynamic array
when we have a different type of data , int , and Char that we dont know the size in the start how to use a dynamic array to store the 2 types
typedef struct personne{
char nom ;
int age ;
}personne;
struct personne saisie_personne_suivante(struct personne* x){
scanf("%s",&x->nom);
scanf("%d",&x->age);
return *x;
}
int main(void){
personne *ali;
ali = malloc(sizeof(char*));
saisie_personne_suivante(ali);
printf("\n %d ",ali->age);
printf("\n %s",&ali->nom);
return 0;
}
Why i dont sucess ?
i think we cant store two types of data at a time in array.If we do so we need to allocate half of memory to char and half to integers provided you should give some size of array.
=>in your program at this line [ali = malloc(sizeof(char*))] you are passsing address of only char not of variable.If you want to store both values just pass address of both int and char.
ali is a pointer to a struct of size sizeof(char) + sizeof(int) which may vary between architectures.
For the time being, let's assume it's 5 bytes (which it probably is on your PC).
What you're doing, is allocate space equal to size of a pointer to char, (which is either 32 or 64bits wide, depending on your OS).
What you probably want to do is allocate space equal to size of your struct (5 bytes), that is:
ali = malloc(sizeof(personne));
Note the lack of *, since you want actual memory for a struct and not a pointer pointing to such a location.
By the way, you wouldn't want to write: malloc(sizeof(char)) either, since that would be just one byte needed for your struct.
I strongly advise you to get your hands on a book on C or a decent tutorial at least.
int main() {
personne *ali;
ali = (struct personne *)malloc(sizeof(personne));
saisie_personne_suivante(ali);
printf("\n %d ", ali->age);
printf("\n %c", ali->nom);
return 0;
}
There is not enough memory for struct personne, so you need to malloc sizeof(personne) memory. nom is not a pointer,it's a char variable,when you print it, use printf("%c",ali->nom);
I can concur with the commenters who recommended a good book/tutorial to get started but nevertheless: here is your repaired code, with a bit of comment.
// printf(), fprintf(), and puts()
#include <stdio.h>
// exit(), malloc(), and scanf()
#include <stdlib.h>
#define PERSONNE_ERROR 0
#define PERSONNE_OK 1
typedef struct personne {
// fixed width for 49 characters and the trailing NUL
char nom[50];
int age;
} personne;
int saisie_personne_suivante(struct personne *x)
{
// For the returns of the scanf()s.
// Because you always check the returns if available
// (well, actually: the returns of printf() et al. rarely get checked)
// preset it to a value meant to say "OK"
int res = PERSONNE_OK;
// UX: let the users know what they are supposed to do.
puts("Your name, please");
// we have a fixed maximum size of name and we can set it here within scanf()
// scanf() returns the number of elements it parsed, *not* the number of characters
// sacnf() needs a pointer to the memory it is expected to put the value into.
// x->nom is already a pointer to a char array, no need to use "&"
if ((res = scanf("%49s", x->nom)) != 1) {
// we can return immediatly here.
// If we would need to cleanup (free memory, for example) we would
// set res to PERSONNE_ERROR and use a goto to jump at the place
// where all the cleanup happens. But that should be done if the clean-up
// is always the same (or could be sorted) and you need such cleanups
// more than just two or three times.
return PERSONNE_ERROR;
}
puts("Your age, too, if you don't mind.");
// x->age is not a pointer to an int, hence we need to prefix "&"
if ((res = scanf("%d", &x->age)) != 1) {
return PERSONNE_ERROR;
}
return res;
}
int main(void)
{
personne *ali;
int res;
// reserve momory for the struct
ali = malloc(sizeof(personne));
// call function that fills the struct and check the return
if ((res = saisie_personne_suivante(ali)) != PERSONNE_OK) {
fprintf(stderr, "Something went wrong with saisie_personne_suivante()\n");
exit(EXIT_FAILURE);
}
// print the content of struct personne
// you can feed printf() directly, no need to find the pointer to the memory
// holding the int
printf("Age: %d\n", ali->age);
// To print strings it needs to know the start of the string whcih needs to be
// a pointer and ali->nom is a pointer to the start of the string
printf("Name: %s\n", ali->nom);
// free allocated memory (not really necessary at the end of the
// program but it's deemed good style and because it costs us nothing
// we cannot find a good reason to skip it)
free(ali);
// exit with a value that tells the OS that this programm ended without an error
// It shoudl be 0 (zero) which it almost always is.
// *Almost* always
exit(EXIT_SUCCESS);
}
But really: go and get some beginners book/tutorial. I cannot give you a recommendation because I don't know about any good ones in your native language (sometimes the english version is good but the translation lacks a lot).
I have the following for my HashTable structure:
typedef char *HashKey;
typedef int HashValue;
typedef struct sHashElement {
HashKey key;
HashValue value;
} HashElement;
typedef struct sHashTable {
HashElement *items;
float loadFactor;
} HashTable;
I never really thought about it until now but I just realized there's two ways how I can use this:
Alternative 1:
void hashInitialize(HashTable *table, int tabSize) {
table->items = malloc(sizeof(HashElement) * tabSize);
if(!table->items) {
perror("malloc");
exit(1);
}
table->items[0].key = "AAA";
table->items[0].value = 45;
table->items[1].key = "BBB";
table->items[1].value = 82;
table->loadFactor = (float)2 / tabSize;
}
int main(void) {
HashTable t1;
int i;
hashInitialize(&t1, HASHSIZE);
for(i = 0; i < HASHSIZE - 1; i++) {
printf("PAIR(%d): %s, %d\n", i+1, t1.items[i].key, t1.items[i].value);
}
printf("LOAD FACTOR: %.2f\n", t1.loadFactor);
return 0;
}
Alternative 2:
void hashInitialize(HashTable **table, int tabSize) {
*table = malloc(sizeof(HashTable));
if(!*table) {
perror("malloc");
exit(1);
}
(*table)->items = malloc(sizeof(HashElement) * tabSize);
if(!(*table)->items) {
perror("malloc");
exit(1);
}
(*table)->items[0].key = "AAA";
(*table)->items[0].value = 45;
(*table)->items[1].key = "BBB";
(*table)->items[1].value = 82;
(*table)->loadFactor = (float)2 / tabSize;
}
int main(void) {
HashTable *t1 = NULL;
int i;
hashInitialize(&t1, HASHSIZE);
for(i = 0; i < HASHSIZE - 1; i++) {
printf("PAIR(%d): %s, %d\n", i+1, t1->items[i].key, t1->items[i].value);
}
printf("LOAD FACTOR: %.2f\n", t1->loadFactor);
return 0;
}
Question 1: They both seem to produce the same result. On main, both examples print the right key/value pair. So, what exactly is the different between them besides the syntax change (using (*table) instead of just table), the extra code to allocate memory for the HashTable structure and the declaration of HashTable pointer?
I've been writing a few data structures lately like stacks, linked lists, binary search trees and now hash tables. And for all of them, I've always used the alternative 2. But now I'm thinking if I could have used alternative 1 and simplify the code, removing most of the * and & that are all over the place.
But I'm asking this question to understand the differences between the two methods and if, and also why, I should use on over the other.
Question 2: As you can see in the structures code, HashKey is a pointer. However, I'm not using strdup nor malloc to allocate space for that string. How and why is this working? Is this OK to do? I've always used malloc or strdup where appropriate when handling dynamic strings or I would get lots of segmentation faults. But this code is not giving me any segmentation faults and I don't understand why and if I should do it like this.
First both solutions are perfectly right !
Alternative 1 :
Your HashTable is declared in the main, which means the struct is somewhere in the call stack. The struct will be destroy if you leave the scope. Note : In your case that can't happen because the declaration is in the main so the scope ends on process exit.
Alternative 2:
You've got a HashTable* (pointer) in the call stack so you need to allocate the memory for the struct. To do so you use malloc.
In both case your struct is correctly allocated. The main difference will be on performances. It's far more performant to allocate on the stack but you can't do dynamic allocation. To do so you need to use malloc.
So, some times, you have to use malloc but try to avoid mallocing a lot if you want to do a high performance application.
Is that clear enough? :)
In alternative 1, the caller would allocate table but your function would allocate the contents thereof, which is not always a good idea in terms of memory management. Alternative 2 keeps all allocations in the same place.
As answered previously, the differences between the two alternatives is memory management. In alternative 1 you expect the caller to allocate the memory for table prior to the call; whereas, in alternative 2 just a pointer declaration is required to give you a place to put the memory after you've created it.
To question 2, the simple answer is that you are assigning a constant to the string. According to the following site the assignment is set up at compile time, not runtime.
http://publications.gbdirect.co.uk/c_book/chapter6/initialization.html
for question 2:
(*table)->items[0].key = "AAA";
actually puts "AAA" in read only parts of memory and char *key points to it, contents pointed by key cannot be changed.
(*table)->items[0].key[0]='a' gives and error
Here you can find further discussion about it.
What is the difference between char s[] and char *s?
The only difference is where the memory comes from -- local variables are typically on the stack whereas mallocs typically come from the heap.