Double pointer vs array of pointers(**array vs *array[]) - c

Im not clearly sure what is the difference between those 2. My professor wrote that **array is same as *array[] and we were presented an example where he used **array (so after classes I tried exchanging that with *array[] and it didn't work), could anyone tell me if those 2 are actually the same as he wrote?? Anyway the class was about dynamic memory allocation
#As soon as I changed the double pointer, this line started throwing error
lines = malloc(sizeof(char*));
and a few others where the memory is beeing reallocated
#2 Hell yeah, here's the whole code
And for those comments bellow, nope there is nothing inside [] because his statement was
**array = *array[]
BIG UPDATE
I am so sorry for any inconvenience, I was just too tired at the time of writing this post, here is the whole code with no edits
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
char **lines; // global text buffer, organized as an array of lines
// --------------------------------------------------------------------------------
// initialize global buffer
void initialize()
{
lines = malloc(sizeof(char*));
lines[0] = NULL;
}
// --------------------------------------------------------------------------------
// return number of lines in buffer
int countLines()
{
int count = 0;
while(lines[count++]) ;
return count-1;
}
// --------------------------------------------------------------------------------
// print one line
void printLine(int line)
{
printf("Line %d: %p %p %s\n",line, &lines[line], lines[line], lines[line]);
}
// --------------------------------------------------------------------------------
// print all lines
void printAll()
{
int num_lines = countLines();
int line = 0;
printf("----- %d line(s) ----\n",num_lines);
while (line < num_lines)
printLine(line++);
printf("---------------------\n");
}
// --------------------------------------------------------------------------------
// free whole buffer
void freeAll()
{
int line = countLines();
while (line >= 0)
free(lines[line--]);
free(lines);
}
// --------------------------------------------------------------------------------
// insert a line before the line specified
void insertLine(int line, char *str)
{
int num_lines = countLines();
// increase lines size by one line pointer:
lines = realloc(lines, (num_lines+2) * sizeof(char*));
// move line pointers backwards:
memmove(&lines[line+1], &lines[line], (num_lines-line+1)*sizeof(char*));
// insert the new line:
lines[line] = malloc(strlen(str)+1);
strcpy(lines[line],str);
}
// --------------------------------------------------------------------------------
// remove the specified line
void removeLine(int line)
{
int num_lines = countLines();
// free the memory used by this line:
free(lines[line]);
// move line pointers forward:
memmove(&lines[line], &lines[line+1], (num_lines-line+1)*sizeof(char*));
// decrease lines size by one line pointer:
lines = realloc(lines, num_lines * sizeof(char*));
}
// --------------------------------------------------------------------------------
// insert a string into specified line at specified column
void insertString(int line, int col, char *str)
{
// make room for the new string:
lines[line] = realloc(lines[line], strlen(lines[line])+strlen(str)+1);
// move characters after col to the end:
memmove(lines[line]+col+strlen(str), lines[line]+col, strlen(lines[line])-col);
// insert string (without terminating 0-byte):
memmove(lines[line]+col, str, strlen(str));
}
// --------------------------------------------------------------------------------
// MAIN program
int main()
{
initialize();
printAll();
insertLine(0,"Das ist");
printAll();
insertLine(1,"Text");
printAll();
insertLine(1,"ein");
printAll();
insertLine(2,"kurzer");
printAll();
printf("lines[2][4] = %c\n",lines[2][4]);
insertString(2,0,"ziemlich ");
printAll();
removeLine(2);
printAll();
freeAll();
return 0;
}

If the code you reference in your question was given to you by your professor as an example of the use of pointer arrays of pointers to pointers, I'm not sure how much good that class will actually do. I suspect it was either provided as a debugging exercise or it may have been your attempt at a solution. Regardless, if you simply compile with Warnings enabled, you will find a number of problems that need attention before you advance to debugging your code.
Regarding the code you reference, while you are free to use a global text buffer, you are far better served by not using a global buffer and passing a pointer to your data as required. There are some instances, various callback functions, etc. that require global data, but as a rule of thumb, those are the exception and not the rule.
Your question basically boils down to "How do I properly use an array of pointers and double-pointers (pointer-to-pointer-to-type) variables. There is no way the topic can be completely covered in one answer because there are far too many situations and contexts where one or the other can be (or should be) used and why. However, a few examples will hopefully help you understand the basic differences.
Starting with the array of pointers to type (e.g. char *array[]). It is generally seen in that form as a function argument. When declared as a variable it is followed with an initialization. e.g.:
char *array[] = { "The quick",
"brown fox",
"jumps over",
"the lazy dog." };
char *array[]; by itself as a variable declaration is invalid due to the missing array size between [..]. When used globally, as in your example, the compiler will accept the declaration, but will warn the declaration is assumed to have one element.
The elements of array declared above are pointers to type char. Specifically, the elements are pointers to the string-literals created by the declaration. Each of the strings can be accessed by the associated pointer in array as array[0], ... array[3].
A pointer to pointer to type (double-pointer), is exactly what its name implies. It is a pointer, that holds a pointer as its value. In basic terms, it is a pointer that points to another pointer. It can be used to access the members of the array above by assigning the address of array like:
char **p = array;
Where p[1] or *(p + 1) points to "brown fox", etc.
Alternatively, a number of pointer to pointer to type can be dynamically allocated and used to create an array of pointers to type, that can then be allocated and reallocated to handle access or storage of an unknown number of elements. For example, a brief example to read an unknown number of lines from stdin, you might see:
#define MAXL 128
#define MAXC 512
...
char **lines = NULL;
char buf[MAXC] = {0};
lines = malloc (MAXL * sizeof *lines);
size_t index = 0;
...
while (fgets (buf, MAXC, stdin)) {
lines[index++] = strdup (buf);
if (index == MAXL)
/* reallocate lines */
}
Above you have lines, a pointer-to-pointer-to-char, initially NULL, that is use to allocate MAXL (128) pointers-to-char. Lines are then read from stdin into buf, after each successful read, memory is allocated to hold the contents of buf and the resulting start address for each block of memory is assigned to each pointer line[index] where index is 0-127, and upon increment of index to 128, index is reallocated to provide additional pointers and the read continues.
What makes the topic larger than can be handled in any one answer is that an array of pointers or pointer to pointer to type can be to any type. (int, struct, or as a member of a struct to different type, or function, etc...) They can be used linked-lists, in the return of directory listings (e.g opendir), or in any additional number of ways. They can be statically initialized, dynamically allocated, passed as function parameters, etc... There are just far too many different contexts to cover them all. But in all instances, they will follow the general rules seen here and in the other answer here and in 1,000's more answers here on StackOverflow.
I'll end with a short example you can use to look at the different basic uses of the array and double-pointer. I have provided additional comments in the source. This just provides a handful of different basic uses and of static declaration and dynamic allocation:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int main (void) {
/* array is a static array of 4 pointers to char, initialized to the
4 string-literals that a part of the declaration */
char *array[] = { "The quick",
"brown fox",
"jumps over",
"the lazy dog." };
/* p is a pointer-to-pointer-to-char assigned the address of array */
char **p = array;
/* lines is a pointer-to-pointer-to-char initialized to NULL, used
below to allocate 8 pointers and storage to hold 2 copes of array */
char **lines = NULL;
size_t narray = sizeof array/sizeof *array;
size_t i;
printf ("\nprinting each string-literal at the address stored by\n"
"each pointer in the array of ponters named 'array':\n\n");
for (i = 0; i < narray; i++)
printf (" %s\n", array[i]);
printf ("\nprinting each string using a pointer to pointer to char 'p':\n\n");
for (i = 0; i < narray; i++, p++)
printf (" %s\n", *p);
p = array;
printf ("\nprinting each line using a pointer to pointer"
" to char 'p' with array notation:\n\n");
for (i = 0; i < narray; i++)
printf (" %s\n", p[i]);
/* allocate 8 pointers to char */
lines = malloc (2 * narray * sizeof *lines);
/* allocate memory and copy 1st 4-strings to lines (long way) */
for (i = 0; i < narray; i++) {
size_t len = strlen (array[i]);
lines[i] = malloc (len * sizeof **lines + 1);
strncpy (lines[i], array[i], len);
lines[i][len] = 0;
}
/* allocate memory and copy 1st 4-strings to lines
(using strdup - short way) */
// for (i = 0; i < narray; i++)
// lines[i] = strdup (array[i]);
/* allocate memory and copy again as last 4-strings in lines */
p = array;
for (i = 0; i < narray; i++, p++)
lines[i+4] = strdup (*p);
p = lines; /* p now points to lines instead of array */
printf ("\nprinting each allocated line in 'lines' using pointer 'p':\n\n");
for (i = 0; i < 2 * narray; i++)
printf (" %s\n", p[i]);
/* free allocated memory */
for (i = 0; i < 2 * narray; i++)
free (lines[i]);
free (lines);
return 0;
}
Let me know if you have any questions. It a large topic with a relatively small set of rules that can be applied in whole lot of different ways and in different contexts.

My professor wrote that **array is same as *array[]
That is true in some contexts and not true in other contexts.
If used in a function as argument,
void foo(int **array) {}
is the same as
void foo(int *array[]) {}
When declared as variables,
int **array;
is not the same as
int *array[];

To Explain in short:
if you want to use a pointer to type, you use *array or *ptr, or whatever variable name .
if you want to use an array of pointers and you already know how many pointers you need before execution (for eg. 10 pointers), then you use *array[10] or *ptr[10];
if you want to use an array of pointers but yet you don't know how many pointers you need before execution, then you use **array or **ptr;
after that you can dynamically allocate memory for every pointer using malloc or new operator to allocate memory for whatever data type you are using, (the data type maybe primitive like int, char ,etc, or it maybe user-defined like struct, etc.

Related

Sorting strings in a program - C [duplicate]

This question already has answers here:
How to qsort an array of pointers to char in C?
(9 answers)
C library function to perform sort
(9 answers)
Dynamically create an array of strings with malloc
(4 answers)
Closed 5 years ago.
So I'm trying to make a program that takes in certain number of strings from stdin and then output into a text file.
The code I have so far is:
#include <stdio.h>
#include <errno.h>
#include <stdlib.h>
#include <string.h>
int cmpstr(const void * a, const void *b){
const char* aa = (const char*) a;
const char* bb = (const char*) b;
return strcmp (aa, bb);
}
int main(int argc, char *argv[]){
int i =0;
int scount;
char ** data = NULL;
FILE * ofile;
if (argc != 3){
printf("%s \n", "The format to use this is: mySort <#of strings> <output filename>",argv[0]);
exit(EXIT_FAILURE);
}
scount = atoi(argv[1]);
if(!scount){
printf("%s \n", "Invalid number.");
exit(EXIT_FAILURE);
}
data = (char **) malloc(scount * sizeof(char*));
if(NULL == data){
printf("Memory allocation failed\n");
exit(EXIT_FAILURE);
}
for(i = 0; i< scount; i++){
if(NULL == fgets(data[i], (int) sizeof(data), stdin)){
printf("Could not get line\n");
exit(EXIT_FAILURE);
}
}
qsort(data, scount, sizeof(char*), cmpstr);
ofile = fopen(argv[2], "w+");
if(ofile == NULL){
printf("Could not open output file. \n");
}
for(i = 0; i<scount; i++){
fputs(data[i], ofile);
}
fclose(ofile);
for(i=0; i<scount; i++){
if(data[i]) free(data[i]);
}
if (data) free(data);
exit (EXIT_SUCCESS);
return 0;
}
However, when I compiled it it gave me a segmentation fault. I tried using the gdb debugger to try and debug it but it did not give me anything really and I barely understand how to use gdb. But my takeaway from the usage of gdb is that there is not enough memory allocated which confuses me since I allocated memory using malloc.
data = (char **) malloc(scount * sizeof(char*));
Here you allocate memory for an array of pointers. You never initialize the contents of that array. Therefore, when you access data[0] below by passing it to fgets, you're accessing an uninitialized pointer object. If you're lucky, the contents of that uninitialized memory constitutes an invalid address, and when fgets attempts to store data there, your program crashes. If you're unlucky, the contents of that uninitialized memory happens to be the address of some block of memory that's used by some other object and you get memory corruption that's really hard to debug.
You need to initialize the pointers allocated by malloc. Like any other pointer object, depending on what you want to do, you can initialize them to NULL, to a pointer to an existing object, or to the result of calling a function such as malloc. In this program, you need to obtain storage for the lines that you're going to read, therefore you'll need to call malloc on each of the lines. Since you don't know in advance how long a line will be, this is best done at the time you read the line.
It would be a good idea to first set all the elements to NULL, as soon as you've allocated the array of pointers, and later allocate memory for the individual lines. You don't have to, but it's easier then to keep track of which elements of the array have been initialized and which ones haven't. In particular, that lets you call free on all the array elements without having to worry how many you've already reached.
fgets(data[i], (int) sizeof(data), stdin)
Passing sizeof(data) here doesn't make sense. The variable data is a pointer to char*, so sizeof(data) is just the size of a pointer. It isn't the size of the array that the pointer points to: that size isn't known at compile time, it's the argument you pass to malloc. And even that size is not relevant here: the size is the maximum number of lines you can read (multiplied by the size of a pointer to a line's contents), but what fgets needs is the size of the memory that's allocated for the line.
To keep things simple, let's say you have a maximum line length max_line_length.
data = (char **) malloc(scount * sizeof(char*));
if (data == NULL) ... // omitted error checking
for (i = 0; i < scount; i++)
data[i] = NULL;
for (i = 0; i < scount; i++) {
data[i] = malloc(max_line_length+2); // +2 for line break character and null byte to terminate the string
if (data[i] == NULL) ... // omitted error checking
if(NULL == fgets(data[i], max_line_length, stdin)) ... // omitted error checking
...
}
After this you'll run into another issue as described in the comments, in that cmpstr receives pointers to pointers to line contents, not pointers to line contents. This is explained in How to qsort an array of pointers to char in C?

What is the C-language statement for function returning a pointer to an array?

What would be the C code for a function that accepts a pointer to a character as argument and returns a pointer to an array of integers?
I have a confusion here. My answer is as follows:
int * q (char *) [ ]
Im not sure if I'm correct. But if its incorrect then what is the correct answer more importantly what is the approach to answer it. In general i would appreciate any general method to learn to interpret such questions and convert them to C code?
When dealing with functions, you basically needs to consider arrays as pointers because it is very hard (if possible) to pass or return an array in a function and make operations such as the sizeof operator still work as intended.
For you purpose, int ** q (char *) is enough, although you would not be able to know the length of the returned array this way.
A pointer to an array of integers looks like:
int (*p)[];
where it is optional to have a dimension inside the square brackets.
So a function returning that would look like:
int (*func(char *))[];
Note that "pointer to array" is a different thing to "pointer to first element of array". Sometimes people say the former when they mean the latter. If you actually meant the latter then your function could be more simply:
int **func(char *);
The first form is rarely used because there is nothing you can do with the return value other than decay it to int ** anyway. It would sometimes be useful to specify a dimension if the function always is to return a pointer to a fixed-size buffer, but in that case I would recommend using a typedef for readability:
typedef int ARR_4_INT[4];
ARR_4_INT * func(char *);
I think I see where your confusion is, and I'm not sure it has been cleared based on the answer you selected. int **q (char *) is a function that returns a pointer to pointer to int, which if that is what you need, that is fine, but understand, the only way a function can return a pointer to pointer to int is if (1) the address of an array of int (pointer to array) is passed as a parameter to q, or (2), pointers are allocated in q and the pointer to allocated pointers is returned.
You appear to want (1), but have selected an answer for (2). Take a look at cdecl.org (C-declarations tool) which can always help decipher declarations
The best way to help you sort it out is probably an example of each. The following examples just plays on the ASCII value of the character variable c (ASCII '5' by default -- decimal 53). In the first case, returning a pointer-to-int (which is a pointer to a block of memory holding zero or more integers). For example, here a block of memory is allocated to hold 53 integers filled with values from 53-105:
#include <stdio.h>
#include <stdlib.h>
int *q (char *c)
{
int *a = calloc (*c, sizeof *a);
if (a)
for (int i = 0; i < (int)*c; i++)
a[i] = *c + i;
return a;
}
int main (int argc, char **argv) {
char c = argc > 1 ? *argv[1] : '5';
int *array = NULL;
if ((array = q (&c)))
for (int i = 0; i < (int)c; i++)
printf ("array[%3d] : %d\n", i, array[i]);
free (array); /* don't forget to free mem */
return 0;
}
Now in the second case, you are returning a pointer-to-pointer-to-int (a pointer to a block of memory holding zero or more pointers to int -- which each in turn can be separately allocated to hold zero or more integers each). In this case each individual pointer is allocated with space to hold one int and the same values as above are assigned:
#include <stdio.h>
#include <stdlib.h>
int **q (char *c)
{
int **a = calloc (*c, sizeof *a); /* allocate *c pointers to int */
if (a) {
for (int i = 0; i < (int)*c; i++)
if ((a[i] = calloc (1, sizeof **a))) /* alloc 1 int per-pointer */
*(a[i]) = *c + i;
else {
fprintf (stderr, "error: memory exhausted.\n");
break;
}
}
return a;
}
int main (int argc, char **argv) {
char c = argc > 1 ? *argv[1] : '5';
int **array = NULL;
if ((array = q (&c)))
for (int i = 0; i < (int)c; i++) {
printf ("array[%3d] : %d\n", i, *(array[i]));
free (array[i]); /* free individually allocated blocks */
}
free (array); /* don't forget to free pointers */
return 0;
}
Example Use/Output
In each case, if no argument is passed to the program, the default output would be:
$ ./bin/qfunction2
array[ 0] : 53
array[ 1] : 54
array[ 2] : 55
...
array[ 50] : 103
array[ 51] : 104
array[ 52] : 105
Now it is entirely unclear which of the two cases you are after as you seem to explain you want a pointer to an array of integers returned. As I started my last answer with, you cannot return an array, all you can return is a pointer, but that pointer can point to a block of memory that can hold multiple integers, or it can point to a block of memory holding multiple pointers that can each in turn be allocated to hold multiple integers.
So the ambiguity comes in "Do you want the return to point to an array of integers or an array of pointers?" int *q (char *) is for the first, int **q (char*) is for the second.
Now, going forward, you will realize that you have not provided a way to know how many integers (or pointers) are being returned. (that requires an extra parameter or global variable (discouraged) at the very least). That is left for another day. (it is also why the examples are a play on the ASCII value of 53 or whatever character is the first character of the first argument, it provides a fixed value to know what has been allocated)
I'm happy to provide further help, but I will need a bit of clarification on what you are trying to accomplish.

How to dynamically allocate memory in an array of strings for some new string and copy that string into the dynamically allocated space in C?

Here is the code that I have:
void InsertStringAt(char *array[], char *s, int pos)
{
if (pos<array.size())
{
*array[pos]=(s *)malloc(sizeof(s));
strcopy(*array[pos], *s);
}
else printf("Position exceeds dimensions of array.");
}
The purpose of this function is to insert the string s into position pos of array[]. Will this code accomplish that?
No, this won't do it:
first you cast the result of malloc to (s *) but s is not a type (it is a variable). Then you allocate room the size of s but s is a pointer, so you allocate only room for a pointer.
Then array is declared as an array of pointers to characters. Now you don't need to dereference array anymore when you access a member. The compiler will do that and if you do that, then there is one dereferencing too many.
Do:
array[pos]= malloc(strlen(s)+1);
Lastly, in C there are no classes so array.size is invalid. You must pass the array size as a separate variable.
May I suggest you return an int to indicate everything was successful? E.g. no out-of-memory and pos < size?
sizeof a pointer simply gives you 8 or 4 (depending on your word size). So to get the length of a string, use strlen() from <string.h>. Also, you needn't cast the return value from malloc. So you'd get:
array[pos] = malloc(strlen(s)+1);
Notice that the dereferencing was removed, since it's already dereferenced.
Also, the function is strcpy() not strcopy(). strcpy() is declared in <string.h>. But strcpy() may lead to buffer overflows, consider making your own:
int safecpy(char *s, const char *t, size_t siz)
{
size_t i;
for (i = 1; (*s = *t) && i < siz; ++i, s++, t++)
;
s[i] = 0; /* null terminate the string */
return i;
}
C arrays do not know their own size; So pass it as a separate argument. It is recommended that sizes are represented with size_t and not int.
Finally, print error messages to stderr, so they don't get pipelined into another program or redirected into a file:
else fprintf(stderr, "Position exceeds dimensions of array.");

Can't copy characters from pointer to another pointer(both with memory allocated)

I have a program that accepts a char input using argv from the command line. I copy the input argv[1] using strcpy to a pointer called structptr(it goes to structptr->words from struct) where memory has been allocated. I then copy character by character from the memory that the pointer structptr points to another pointer called words that points to memory that has been allocated. After i've copied one character i print that element [c] to make sure that it has been copied correctly(which it has). I then finish copying all of the characters and return the result to a char pointer but for some reason it is blank/null. After each copying of the characters i checked if the previous elements were correct but they don't show up anymore([c-2], [c-1], [c]). Here is my code:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
struct StructHolder {
char *words;
};
typedef struct StructHolder Holder;
char *GetCharacters(Holder *ptr){
int i=0;
char *words=malloc(sizeof(char));
for(i;i<strlen(ptr->words);i++){
words[i]=ptr->words[i];
words=realloc(words,sizeof(char)+i);
}
words[strlen(ptr->words)]='\0';
return words;
}
int main(int argc, char **argv){
Holder *structptr=malloc(sizeof(Holder));
structptr->words=malloc(strlen(argv[1]));
strcpy(structptr->words, argv[1]);
char *charptr;
charptr=(GetCharacters(structptr));
printf("%s\n", charptr);
return 0;
At first I thought this was the problem:
char *words=malloc(sizeof(char)) is allocating 1 byte (sizeof 1 char). You probably meant char *words = malloc(strlen(ptr->words)+1); - You probably want to null check the ptr and it's member just to be safe.
Then I saw the realloc. Your realloc is always 1 char short. When i = 0 you allocate 1 byte then hit the loop, increment i and put a char 1 past the end of the realloced array (at index 1)
Also your strcpy in main is has not allocated any memory in the holder.
In these two lines,
structptr->words=malloc(strlen(argv[1]));
strcpy(structptr->words, argv[1]);
need to add one to the size to hold the nul-terminator. strlen(argv[1]) should be strlen(argv[1])+1.
I think the same thing is happening in the loop, and it should be larger by 1. And sizeof(char) is always 1 by definition, so:
...
words=realloc(words,i+2);
}
words=realloc(words,i+2); // one more time to make room for the '\0'
words[strlen(ptr->words)]='\0';
FYI: Your description talks about structptr but your code uses struct StructHolder and Holder.
This code is a disaster:
char *GetCharacters(Holder *ptr){
int i=0;
char *words=malloc(sizeof(char));
for(i;i<strlen(ptr->words);i++){
words[i]=ptr->words[i];
words=realloc(words,sizeof(char)+i);
}
words[strlen(ptr->words)]='\0';
return words;
}
It should be:
char *GetCharacters(const Holder *ptr)
{
char *words = malloc(strlen(ptr->words) + 1);
if (words != 0)
strcpy(words, ptr->words);
return words;
}
Or even:
char *GetCharacters(const Holder *ptr)
{
return strdup(ptr->words);
}
And all of those accept that passing the structure type makes sense; there's no obvious reason why you don't just pass the const char *words instead.
Dissecting the 'disaster' (and ignoring the argument type):
char *GetCharacters(Holder *ptr){
int i=0;
OK so far, though you're not going to change the structure so it could be a const Holder *ptr argument.
char *words=malloc(sizeof(char));
Allocating one byte is expensive — more costly than calling strlen(). This is not a good start, though of itself, it is not wrong. You do not, however, check that the memory allocation succeeded. That is a mistake.
for(i;i<strlen(ptr->words);i++){
The i; first term is plain weird. You could write for (i = 0; ... (and possibly omit the initializer in the definition of i, or you could write for (int i = 0; ....
Using strlen() repeatedly in a loop like that is bad news too. You should be using:
int len = strlen(ptr->words);
for (i = 0; i < len; i++)
Next:
words[i]=ptr->words[i];
This assignment is not a problem.
words=realloc(words,sizeof(char)+i);
This realloc() assignment is a problem. If you get back a null pointer, you've lost the only reference to the previously allocated memory. You need, therefore, to save the return value separately, test it, and only assign if successful:
void *space = realloc(words, i + 2); // When i = 0, allocate 2 bytes.
if (space == 0)
break;
words = space;
This would be better/safer. It isn't completely clean; it might be better to replace break; with { free(words); return 0; } to do an early exit. But this whole business of allocating one byte at a time is not the right way to do it. You should work out how much space to allocate, then allocate it all at once.
}
words[strlen(ptr->words)]='\0';
You could avoid recalculating the length by using i instead of strlen(ptr->words). This would have the side benefit of being correct if the if (space == 0) break; was executed.
return words;
}
The rest of this function is OK.
I haven't spent time analyzing main(); it is not, however, problem-free.

How do I dynamically allocate an array of strings in C?

If I have the number of items in a var called "totalstrings" and a var called "string size" that is the string size of each item, how do I dynamically allocate an array called "array?"
This is an array of strings in C, not C++.
Thanks!
NOTE: My examples are not checking for NULL returns from malloc()... you really should do that though; you will crash if you try to use a NULL pointer.
First you have to create an array of char pointers, one for each string (char *):
char **array = malloc(totalstrings * sizeof(char *));
Next you need to allocate space for each string:
int i;
for (i = 0; i < totalstrings; ++i) {
array[i] = (char *)malloc(stringsize+1);
}
When you're done using the array, you must remember to free() each of the pointers you've allocated. That is, loop through the array calling free() on each of its elements, and finally free(array) as well.
The common idiom for allocating an N by M array of any type T is
T **a = malloc(N * sizeof *a);
if (a)
for (i = 0; i < N; i++)
a[i] = malloc(M * sizeof *a[i]);
As of the 1989 standard, you don't need to cast the result of malloc, and in fact doing so is considered bad practice (it can suppress a useful diagnostic if you forget to include stdlib.h or otherwise don't have a prototype for malloc in scope). Earlier versions of C had malloc return char *, so the cast was necessary, but the odds of you having to work with a pre-1989 compiler are pretty remote at this point. C++ does require the cast, but if you're writing C++ you should be using the new operator.
Secondly, note that I'm applying the sizeof operator to the object being allocated; the type of the expression *a is T *, and the type of *a[i] is T (where in your case, T == char). This way you don't have to worry about keeping the sizeof expression in sync with the type of the object being allocated. IOW, if you decide to use wchar instead of char, you only need to make that change in one place.
char** stringList = (char**)malloc(totalStrings * sizeof(char*));
for( i=0; i<totalStrings; i++ ) {
stringList[i] = (char*)malloc(stringSize[i]+1);
}
I know this question is old and was already answered. I just want to point out that malloc is a system call and shouldn't be used multiple times.
It would be better to allocate one big chunk of memory and make the array point to it. Something like this :
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define STR_SIZE 100 //STR_SIZE doesn't have to be a constant
int main(){
int i;
char **arr;
char *long_string;
long_string = (char *)malloc(sizeof(char)*STR_SIZE*10);
arr = malloc(sizeof(char *)*10);
//Pointing each item of the array to an allocated memory.
for (i=0; i<10; i++){
arr[i] = (long_string + STR_SIZE * i);
}
//Initialising the array
for (i=0; i<10; i++){
strcpy(arr[i], "This is a line in a\
paragraph\n");
}
//Printing the items of the array
for (i=0; i<10; i++){
printf("%s \n", arr[i]);
}
//freeing the allocated memory
free(long_string);
free(arr);
return 0;
}
Well, first you might want to allocate space for "array", which would be an array of char * that is "totalstrings" long.
What would then be the starting and final indexes in "array"? You know the first one is 0; what's the last one?
Then, for each entry in "array", you could (if you wanted) allocate one area of memory that is "stringsize+1" (why +1, pray tell me?) long, putting the starting address of that area -- that string -- into the correct member of "array."
That would be a good start, imo.

Resources