• Status: Solved
  • Priority: Medium
  • Security: Public
  • Views: 268
  • Last Modified:

memory allocation question

The code to the program is at www.losingfast.com/code.txt
rather long so i posted it there

This is a homework program thats just suppose to take an array of names...of format lastname,firstname,age as input and sorts it by either last first or age determined by a command line input flag.  However...in my program when the number of names gets over 8...i get a seg fault..=/

when i run gdb, it says
Enter name 1:lkdsjfladsfjlksdj,3jkl3jlk4jlk3j4,3
Enter name 2:lkjlksdfjlkdlsflsdfj,jlkjlkjkljlkkl3,3
Enter name 3:klsdfjlkjsdlflsk,jlkdsfjlksdjflkjlskdfj,5
Enter name 4:jsdlkflksdhgsdl,sdjflkjdskljflsdjlkfj,3
Enter name 5:kldfjslkfjksdlg,djlkfjskdgjlsdgklh,3
Enter name 6:jdlskjlfgsdhglklksdghl,343,3
Enter name 7:ldskjfksjdklfjsldflk,3434343j,3
Enter name 8:ksdjglksdhgsdhkg,3jlkjlkjkljlk3,3
Enter name 9:lskdglkdslghsledg,8,7

Program received signal SIGSEGV, Segmentation fault.
0x400c49dd in strcpy () from /lib/libc.so.6


char * allocate( int num){
char * numbers;
numbers = (char *) calloc (num, sizeof(char));

return numbers;

the above is how i'm allocating memory..am i doing this right?
0
AZN_Wang3
Asked:
AZN_Wang3
1 Solution
 
umangjoshiCommented:
pls use the structure

struct member
{
   char fname[20];
   char lname[20];
   int age;
};

then define an array of struct member


--------------
or with same structure, add one more thing
struct member *next;

and use linked list
0
 
gj62Commented:
No,

What you have done is allocate just the pointers to the names, not the space to store the names.

Think of it this way - your array is an array of pointers - not strings.

char **names; means a pointer to a pointer (in this case, it will be an array of pointers to pointers).

So you first have to make the array of pointers:

names = (char **)malloc(num*sizeof(char*));

Then you have to make room for each of the strings:

for (i = 0; i < num; ++i)
{
  names[i] = (char *)malloc(MAX*sizeof(char));
}

Because this is homework, I'll let you figure out how to put it into your program.

Just a question - why not use a struct to hold everything?  That's probably not the assignment, but it is a much better way of organizing everything...

NOTE: You use MAX in your program, but it is never defined...
0
 
gj62Commented:
It is generally considered bad form to have string space in a struct when it can be variable lengths.  I would use the following struct:

struct STUDENT
{
  char *firstName;
  char *lastName;
  int age;
};

and then malloc the string space required for each name after you read it in - that way you really only need to have one variable that has string space long enough to hold the longest name, e.g.

char tempName[100];

but you don't waste any space in your structs...

Also, you can allocate your array of structs dynamically as well, using realloc() and not have to statically declare them....
0
Concerto's Cloud Advisory Services

Want to avoid the missteps to gaining all the benefits of the cloud? Learn more about the different assessment options from our Cloud Advisory team.

 
Kent OlsenData Warehouse Architect / DBACommented:
>> char **names; means a pointer to a pointer (in this case, it will be an array of pointers to pointers).

Nahhh.  One too many dereferences.  :)  It's an array of pointers to strings, not unlike names[][].


>> It is generally considered bad form to have string space in a struct when it can be variable lengths.  I would use the following struct:

GJ's correct here.  Unless you're reading fixed-length data from a file or will be writing to one, avoid fixed length strings within structs.  (They may be a convenient starting point, but can cause all kinds of headaches as a program develops.)


typdef struct
{
  char Name[20];
} TStruct1;

typedef struct
{
  char *Name;
} TStruct2;

TStruct1 Struct1;
TStruct2 Struct2;

Struct2.Name = (char *)malloc (strlen ("This String"));
strcpy (Struct2.Name, "This String");
strcpy (Struct1.Name, "This String");

In both structures Name is "This String".  Note that the code to access the Name field is the same in both structs.

strcmp (Struct1.Name, Struct2.Name)

And it's a snap to put "This is a very long string that I want to use for the 'Name' field" into struct2, but impossible with struct1.


Regarding the original question:

char * allocate( int num){
  char * numbers;
  numbers = (char *) calloc (num, sizeof(char));
  return numbers;
}

calloc() is a poor choice of API here.  You really want to allocate a buffer large enough to hold "num" characters so malloc() is a better choice.  If you were requesting a table of structs, or pointers, calloc() would be a better fit.

Both will work.  But malloc() is the better choice here.

Kdo
0
 
gj62Commented:
Kdo,

Semantically, char **p is a pointer to a pointer.  Dereference it once and you have a char *.  

I agree, it is an array of pointers to strings - but what is a string, but a char *  ?

Be careful though...

char **p is similar but different from char p[][];  

You can't use them interchangeably...

0
 
Kent OlsenData Warehouse Architect / DBACommented:
Sorry Gj -- I wasn't specific enough.  As you said, **names is a pointer to a pointer.  However it is NOT an array of pointers to pointers, but it can be used as an array of pointers to strings.

'not unlike names[][]' was a poor example on my part.

I hate Mondays.  Particularly this one.

Kdo
0
 
gj62Commented:
Got it - cold, grey and rainy here, just to top off a perfect start to a long week.
0
 
AZN_Wang3Author Commented:
Thx GJ, i got it to work now
Can you explain a little further what i'm doing wrong?
for the struct part...we didn't learn that yet in our class

for allocating dynamic memorry for 2d arrys... i needed to allocated enough buffer for each array[i] ?
0
 
gj62Commented:
Got it - cold, grey and rainy here, just to top off a perfect start to a long week.
0
 
gj62Commented:
OK, no structs.

Yes, you need to allocate space for whatever array[i] is pointing to. Remeber, you are NOT allocating a 2D array - you have single array, that contains pointers.  Those pointers may not point to contiguous memory, like a 2D array.

If you want a 2D array (and it really is not a good idea when working with strings - I'll get to why in a moment), you would declare

char names[20][50];

That would create an array of 20 strings, each string 50 long, and it would be contiguous in memory.

Now, why don't you want to do this?  First, there really isn't any advantage to having it contiguous in memory - at least not for unformatted strings of varying length.  Second, both dimensions are fixed at compile-time.  Third, if you get to sorting, it is much easier to just sort the array of pointers, rather than moving all the strings.

With an array of pointers to strings, you can allocate each string exactly the size it needs to be.  In my example, I allocated all the strings to size MAX, but you could just as easily put the allocation in the loop where the names are input, have the name input into a temporary buffer of a large size, then malloc() only what you need by using strlen() on the temporary buffer once the name was entered.

Remember, in my example first malloc simply allocates space for an array of pointers - that's it.  Each array element can now hold a pointer to somewhere else in memory.  

To create each pointer in the array, you have to use malloc() or some other form of memory allocation.  




0
 
gj62Commented:
If you do allocate "just enough space" using strlen, remember to increase the size by 1 - you need it for the NULL.
0

Featured Post

Independent Software Vendors: We Want Your Opinion

We value your feedback.

Take our survey and automatically be enter to win anyone of the following:
Yeti Cooler, Amazon eGift Card, and Movie eGift Card!

Tackle projects and never again get stuck behind a technical roadblock.
Join Now