Computer Science Canada

Array of C-strings

Author:  Anon [ Thu Feb 21, 2008 11:01 pm ]
Post subject:  Array of C-strings

I'm a little confused on how to implement this properly. (Actually this exercise showed me I'm not sure how to do dynamic 2d arrays either in C)

What I'm trying to do is declare a dynamic 2d array of char. So what tried is:
This code, either segfaults or causes windows to assume I have a trojan, depending on luck.

code:

//counters declared at start of code

  char** start = malloc(11*sizeof(char));
  for (i=0;i<10;i++) {
        start[i] = malloc(11*sizeof(char));
  }

  for (i=0;i<10;i++) {
        free(start[i]);
  }


My understanding of pointers/arrays in C is that should work, since I'm allocating spaced for 11 ptrs to char, and then allocating space to each of those ptrs for 11 chars.
Could someone point out where I'm going wrong? My guess was that since C allocates arrays as a bunch of sequential memory addresses, it might be the the for loop allocating blocks of memory to each array element that is screwing things up, but if thats the case then I'm obviously going about the whole process wrong.

Also, this is a little off-topic, but I dont think it merits it's own topic, I've noticed that some C-compilers support variable declarations in the middle of a block (inline declarations? I think thats the right term), while others require all variables to be declared at the start. Which is the ANSI standard?

EDIT:

Figured it out not three seconds after posting. Or so I hope. I was allocating space for a char, not a char* in the initial allocation. changing above to:

code:

//counters declared at start of code

  char** start = malloc(11*sizeof(char*));
  for (i=0;i<10;i++) {
        start[i] = malloc(11*sizeof(char));
  }

  for (i=0;i<10;i++) {
        free(start[i]);
  }


makes it run. Would still appreciate feedback if this is a correct and safe way to intialize a 2d array

Author:  OneOffDriveByPoster [ Thu Feb 21, 2008 11:14 pm ]
Post subject:  Re: Array of C-strings

Anon @ Thu Feb 21, 2008 11:01 pm wrote:
code:

//counters declared at start of code

  char** start = malloc(11*sizeof(char*));
  for (i=0;i<10;i++) {
        start[i] = malloc(11*sizeof(char));
  }

  for (i=0;i<10;i++) {
        free(start[i]);
  }
You are apparently making space for 11 pointers-to-char but only using 10. You can also free _start_ if you are done with it. Set the pointer to NULL after freeing it (just a good idea). Also, sizeof(char) is always 1 in standard C.

Author:  Anon [ Thu Feb 21, 2008 11:58 pm ]
Post subject:  Re: Array of C-strings

Thanks, for the help!
So, factoring your suggestions into my code I get:

code:


//counters declared at start of code

  char** start = malloc(10);
  for (i=0;i<10;i++) {
   start[i] = malloc(11); //need 1 extra here only for null terminator
  }

  for (i=0;i<10;i++) {
   free(start[i]);
  }

free(start); //free "start" as well
start = NULL; //set start to NULL


Is this now safe/correct?

Thanks again for the help!

Author:  md [ Fri Feb 22, 2008 12:43 am ]
Post subject:  RE:Array of C-strings

if your making strings of length 10, yes.

Author:  OneOffDriveByPoster [ Fri Feb 22, 2008 11:14 am ]
Post subject:  Re: Array of C-strings

Anon @ Thu Feb 21, 2008 11:58 pm wrote:
code:
  char** start = malloc(10);
sizeof(char *) again, can be different from sizeof(char). Anyhow, there is no value proposition to doing what you are doing unless if your arrays do change size. Maybe you should try that out?

Author:  md [ Fri Feb 22, 2008 12:00 pm ]
Post subject:  RE:Array of C-strings

I actually missed that; sizeof(char*) is 4 on most 32bit computers. it isn't however guaranteed to be so.

Using sizeof(char) and sizeof(char*) is always the best thing to do anyways, since it helps show where your numbers are coming from (magic numbers are bad mkay?)

Author:  OneOffDriveByPoster [ Fri Feb 22, 2008 4:20 pm ]
Post subject:  Re: RE:Array of C-strings

md @ Fri Feb 22, 2008 12:00 pm wrote:
(magic numbers are bad mkay?)
I would agree, but 0 and 1 should be somewhat acceptable. AFAIK, writing sizeof(char) in this context is only good for reminding poeple when they change the type that is being allocated.

Author:  Anon [ Sat Feb 23, 2008 6:40 pm ]
Post subject:  Re: Array of C-strings

OneOffDriveByPoster @ Fri Feb 22, 2008 11:14 am wrote:
Anon @ Thu Feb 21, 2008 11:58 pm wrote:
code:
  char** start = malloc(10);
sizeof(char *) again, can be different from sizeof(char). Anyhow, there is no value proposition to doing what you are doing unless if your arrays do change size. Maybe you should try that out?

yeah, I noticed that, another stupid mistake on my part. Embarassed
It seems to me that using these numeric constants is a bad idea in terms of coding style, but it sounds reasonable that chars would be 1 byte on every compiler, so perhaps a preprocessor 'define' would make the code more readable?

code:


#ifndef SIZE_OF_CHAR
#define SIZE_OF_CHAR 1
#endif


would that be better style?

Oh, and actually the only reason I'm using dynamic mem, is because I have to have a function return the result of the operations to this array, and in order to stop the variable going out of scope when the function ends, I have to return the address of the pointer. If there is a way to return a statically allocated array without having it go out of scope, I'm all ears. (Also, using 'static' wont work in this case, as I need to have a unique array each time the function is called)

Author:  md [ Sat Feb 23, 2008 6:55 pm ]
Post subject:  RE:Array of C-strings

the size of a character is not always 1; though for any code you write it almost certainly will be. That's the reason you use sizeof(); C++ doesn't guarantee a fixed size, only a minimum size.

Author:  OneOffDriveByPoster [ Sat Feb 23, 2008 10:23 pm ]
Post subject:  Re: RE:Array of C-strings

md @ Sat Feb 23, 2008 6:55 pm wrote:
the size of a character is not always 1
We are talking about C, and sizeof(char) is always 1 or else your compiler is not worth using. The same is true for C++. You may be thinking of a character literal, or wchar_t or something.

Author:  OneOffDriveByPoster [ Sat Feb 23, 2008 10:35 pm ]
Post subject:  Re: Array of C-strings

Anon @ Sat Feb 23, 2008 6:40 pm wrote:
would that be better style?
No, use sizeof if feel that you must.

Quote:
Oh, and actually the only reason I'm using dynamic mem, is because I have to have a function return the result of the operations to this array, and in order to stop the variable going out of scope when the function ends, I have to return the address of the pointer. If there is a way to return a statically allocated array without having it go out of scope, I'm all ears. (Also, using 'static' wont work in this case, as I need to have a unique array each time the function is called)
Consider having the caller pass you the array. You may be able to avoid using dynamic memory that way. Even if you still have to use dynamic memory, at least the caller should know to clean up after itself.

Author:  Anon [ Sun Feb 24, 2008 11:37 am ]
Post subject:  Re: Array of C-strings

OneOffDriveByPoster @ Sat Feb 23, 2008 10:35 pm wrote:
Anon @ Sat Feb 23, 2008 6:40 pm wrote:
would that be better style?
No, use sizeof if feel that you must.

Quote:
Oh, and actually the only reason I'm using dynamic mem, is because I have to have a function return the result of the operations to this array, and in order to stop the variable going out of scope when the function ends, I have to return the address of the pointer. If there is a way to return a statically allocated array without having it go out of scope, I'm all ears. (Also, using 'static' wont work in this case, as I need to have a unique array each time the function is called)
Consider having the caller pass you the array. You may be able to avoid using dynamic memory that way. Even if you still have to use dynamic memory, at least the caller should know to clean up after itself.


Hmmm... that would work for this case, and save me a lot of hassle. Oh well, I still got to learn a little about dynamically allocated memory Very Happy

Thanks md and OneOffDriveByPoster!

EDIT:

I was playing around with my program trying to clean it up and stuff when I thought of another way to return a static array: wrap it inside a struct
code:

struct grid{
    char grid[MAX][MAX]; //assume MAX is a preprocessor constant
};

typedef struct grid grid;

//to return this I would go

grid some_function();


I got the idea from OOP class wrappers. Would this be appropriate coding style, or is this something I should save for OOP languages?

Author:  md [ Sun Feb 24, 2008 6:45 pm ]
Post subject:  RE:Array of C-strings

that works too; also you can do

C:
typedef struct _grid { ...} grid;

Author:  OneOffDriveByPoster [ Sun Feb 24, 2008 8:47 pm ]
Post subject:  Re: Array of C-strings

Anon @ Sun Feb 24, 2008 11:37 am wrote:
code:
grid some_function();
The primary disadvantage is that you are really copying the array. Note that what you are doing is likely having an automatic array inside the function, and even if it is a static array, you are getting a temporary created (and associated copying) when you return the aggregate from the function. If you are doing assignment after, you copy yet again. If you expect a compiler to optimize this away then let us hope you have one with good Inter-Procedural Analysis. (It is likely that a compiler could take care of the last copy when you are assigning the result directly).

Author:  md [ Sun Feb 24, 2008 11:18 pm ]
Post subject:  RE:Array of C-strings

There's that too... which can be solved with more pointers!

Just return a pointer to a grid; which you can easliy make with malloc(sizeof(grid))

Author:  Anon [ Mon Feb 25, 2008 11:32 pm ]
Post subject:  Re: Array of C-strings

OneOffDriveByPoster @ Sun Feb 24, 2008 8:47 pm wrote:
Anon @ Sun Feb 24, 2008 11:37 am wrote:
code:
grid some_function();
The primary disadvantage is that you are really copying the array. Note that what you are doing is likely having an automatic array inside the function, and even if it is a static array, you are getting a temporary created (and associated copying) when you return the aggregate from the function. If you are doing assignment after, you copy yet again. If you expect a compiler to optimize this away then let us hope you have one with good Inter-Procedural Analysis. (It is likely that a compiler could take care of the last copy when you are assigning the result directly).



*slaps forehead*

Yes, I realize I'd have to return a pointer to the grid, as md has already said. Also, I'd guess that whilst passing in an array is the same as passing in a pointer, passing in a struct as a parameter by value is probably rather inefficient.

I'm curious though, is using a struct to contain the array, and then using a pointer to said struct a good way to allocate space for N-dimensional arrays? Because to allocate for each block iteratively would seem like a lot of needless overhead for N>2. If a more compact method exists, I'd love to hear about it!

Again, thanks for the helpful comments!

Author:  OneOffDriveByPoster [ Mon Feb 25, 2008 11:59 pm ]
Post subject:  Re: Array of C-strings

Anon @ Mon Feb 25, 2008 11:32 pm wrote:
Because to allocate for each block iteratively would seem like a lot of needless overhead for N>2. If a more compact method exists, I'd love to hear about it!
You would need to do it that way if you have a jagged array. Since you do not, and your sub-dimension sizes are fixed, using a struct works great. If you do not have a jagged array but your sizes are not fixed, you could allocate a big block and refer to it through a pointer to VLA (I think).


: