When I use qsort() in the C on my Mac, these code works well, It can sort every lines in one file well.
int compare(const void *p, const void *q) {
return strcmp(p,q);
}
void function_name(){
char buf[1024][1024];
int i=0;
FILE * fp;
if(!(fp=fopen(filename,"r"))){
perror("Open error!");
exit(0);
}
while(fgets(buf[i],1024,fp)){
//printf("%s",buf[i]);
i++;
}
qsort(buf, i, sizeof(buf[0]), compare);
}
However, when I use malloc to assign the space, it sucks. Why is that?
The code below shows I use malloc to make one two-dimension array. I print the content of buf before and after. It seems that lose all the information.
int i=0;
FILE * fp;
char ** buf;
buf = (char **)malloc(sizeof(char*)*1024);
if(!(fp=fopen(filename,"r"))){
perror("Open error!");
exit(0);
}
buf[0]=(char *)malloc(sizeof(char)*1024);
while(fgets(buf[i],1024,fp)){
i++;
buf[i]=(char *)malloc(sizeof(char)*1024);
}
for(int j=0;j<i;j++){
printf("%s",buf[j]);
}
printf("hehe%ld\n",sizeof(char)*1024);
qsort(buf, i, sizeof(char)*1024, compare);
printf("hehe\n");
for(int j=0;j<i;j++){
printf("%s",buf[j]);
}
output:
a
A
b
c
d
D
C
E
e
B
d
e
f
a
hehe1024
hehe
(null)(null)(null)(null)(null)(null)(null)(null)(null)(null)(null)(null)(null)(null)(null)(null)
Most important, how to fix my malloc version?
When you attempt to qsort buf declared as char **buf, you are using the wrong comparison function. As I noted in the comment, char buf[x][y] is an x array of character arrays of y chars, e.g. char (*)[y] when passed as a parameter. When you declare buf as char **buf;, you declare a pointer to a pointer to type char. In either case, you have a pointer to string, and you must dereference each value passed to qsort one additional level of indirection., e.g.
int cmpstrings (const void *a, const void *b) {
return strcmp (*(char * const *)a, *(char * const *)b);
}
A short example using char **buf; would be:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
/* qsort string comparison - for pointer to pointer to char */
int cmpstrings (const void *a, const void *b) {
return strcmp (*(char * const *)a, *(char * const *)b);
}
int main (void) {
char *ap[] = { "This is a tale",
"of captian Jack Sparrow",
"a pirate so brave",
"on the seven seas." },
**buf = NULL;
int n = sizeof ap/sizeof *ap;
if (!(buf = malloc (n * sizeof *buf))) { /* allocate pointers */
fprintf (stderr, "error: virtual memory exhausted.\n");
return 1;
}
for (int i = 0; i < n; i++)
buf[i] = strdup (ap[i]); /* allocate/copy strings */
qsort (buf, n, sizeof *buf, cmpstrings);
for (int i = 0; i < n; i++) { /* print and free */
printf ("buf[%d] : %s\n", i, buf[i]);
free (buf[i]);
}
free (buf);
return 0;
}
Example
$ ./bin/qsortptp
buf[0] : This is a tale
buf[1] : a pirate so brave
buf[2] : of captian Jack Sparrow
buf[3] : on the seven seas.
qsort, memcpy and similar functions assumes that the pointer passed points at an array. The very definition of an array is x number of items allocated contiguously, in adjacent memory cells. For example char array [x][y];.
There is wide-spread confusion about the use of pointer-to-pointers. There's an old trick you can use to declare a look-up table, where each item points to an array of variable length, which goes like this:
char** ptr = malloc(x * sizeof(char*));
for(int i=0; i<x; i++)
{
ptr[i] = malloc(y * sizeof(char));
}
This allows you to access the look-up table with array-like syntax, ptr[i][j]. But that does not mean that this is an array, there is no relation whatsoever beween a pointer-to-pointer and a 2D array! This is rather x number of segments, where each segment allocated at any place on the heap.
The only reason why you would ever use the above pointer-to-pointer trick is when you must have variable length for each item in the look-up table. If you don't need that, then the above method is plain bad and always incorrect - it is much slower than a real array, both in terms of allocation overhead, heap fragmentation and poor data cache use. And as you discovered, it can't even be used as an array... because it isn't one.
Now there are unfortunately numerous incompetent would-be gurus all over the world incorrectly teaching the above as the way to allocate a multi-dimensional array dynamically. Which is complete nonsense. It is not a multi-dimensional array and can't be used as one. See this for an explanation of how you actually should allocate multi-dimensional arrays dynamically.
Related
This is what I expect my string array s to be after the program is run: {"#0", "#1", "2"}.
This is what I am getting: {"#2", "#2", "2"}.
How do I modify this code so that I can get {"#0", "#1", "#2"} in the main after the function is executed?
What am I doing wrong? Please help.
#include <stdio.h>
void func(char **s){
for(int i=0; i<3; i++){
char buf[10];
snprintf(buf, 10, "#%d",i);
s[i]=buf;
}
}
int main()
{
char *s[3];
func(s);
for(int i=0; i<3; i++){
printf("%s", s[i]);
}
return 0;
}
First, you have every element in your array pointing to the same character array.
Second, they are all pointing to a local character array. This leads to undefined behavior.
Local variables in functions get allocated on the stack. When the function call is over, that memory may be overwritten with some other value.
Given two pointers p and q, the statement:
p = q;
doesn't copy the contents of the memory pointed to by q to the contents of the memory pointed to by p. It copies the pointer values, such that both p and q now point to the same memory, and any change to the memory via p is reflected when q is used.
That being said, the statement:
char buf[10];
declares buf to be an array of 10 chars. It has a lifetime corresponding to the execution of its block of definition. Once the function returns, it's destroyed and s is now indeterminate. Indeterminate pointers lead to undefined behaviour.
Possible Solutions:
standard strcpy
POSIX's strdup (which will be included in C23)
Note that the strdup() function returns a pointer to a new string which is
a duplicate of the provided string. Memory for the new string is obtained with malloc, and must be freed by the calling process with free.
#Chris’s answer tells you what is wrong.
To fix it, you have options. The simplest is to make the argument array have strings (char arrays) that are big enough for your uses:
#define MAX_STR_LEN (9+1) // Every string’s capacity is 9+1 characters
void func(size_t n, char array_of_string[][MAX_STR_LEN])
{
for (size_t i=0; i<n; i++)
{
snprintf(array_of_string[i], MAX_STR_LEN, "#%d", (int)i); // use the extant string
}
}
int main(void)
{
char array_of_string[3][MAX_STR_LEN] = {{0}}; // Array of 3 strings
func(3, array_of_string);
...
return 0;
}
If you want to play with dynamic char * strings, life gets only a little more complicated:
void func(size_t n, char *array_of_string[])
{
for (size_t i=0; i<n; i++)
{
free(array_of_string[i]); // free any pre-existing string
array_of_string[i] = calloc( 10, 1 ); // allocate our new string
if (!array_of_string[i]) fooey(); // always check for failure
snprintf(array_of_string[i], 10, "#%d", (int)i); // use the new string
}
}
int main(void)
{
char *array_of_string[3] = {NULL}; // Array of 3 dynamic strings, all initially NULL
func(3, array_of_string);
...
for (size_t i=0; i<3; i++) // Don’t forget to clean up after yourself
free(array_of_string[i]);
return 0;
}
Ultimately the trick is to manage the size of your strings, remembering that a string is itself just an array of char. You must ensure that there is enough room in your character array to store all the characters you wish. (Good job on using snprintf()!
Also remember that in C any argument of the form array[] is the same as *array. So our functions could have been written:
void func(size_t n, char (*array_of_string)[MAX_STR_LEN])
or
void func(size_t n, char **array_of_string)
respectively. The first is an uglier (harder to read) syntax. The second is nicer, methinks, but YRMV.
Finally, if you are using C99 (or later) you can tell the compiler that those arguments are, actually, arrays:
void func(size_t n, char array_of_string[n][MAX_STR_LEN])
or
void func(size_t n, char *array_of_string[n])
MSVC does not support that syntax, though, and probably never will, alas.
{ // start of a new scope
char buf[10]; // a variable with automatic storage duration
// ...
} // end of scope - all automatic variables end their life
In your code, you make pointers point at buf which has seized to exist (3 times) at the } in the for loop. Dereferencing (reading from the memory those pointers point at) those pointers afterwards makes your program have undefined behavior (anything could happen).
What you can do is to allocate and release memory dynamically using malloc and free.
When sending in a pointer to the first element in an array of elements to a function like you do, it's also customary to provide the length of the array (the number of elements in the array) to the function.
It could look like this:
#include <stdio.h>
#include <stdlib.h>
// A macro to calculate the number of elements in an array
// sizeof (x) - the number of bytes the whole array occupies
// sizeof *(x) - the size of the first element in the array
// (all elements have equal size)
// The result of the division is the number of elements in the array.
#define SIZE(x) (sizeof (x) / sizeof *(x))
void func(char *s[], size_t len) {
for (size_t i = 0; i < len; i++) {
// calculate the required length for this string
size_t req = snprintf(NULL, 0, "#%zu", i) + 1; // +1 for '\0'
// and allocate memory for it
s[i] = malloc(req);
if(s[i] == NULL) exit(1); // failed to allocate memory
snprintf(s[i], req, "#%zu", i);
} // dynamically allocated memory is _not_ released at the end of the scope
}
int main() {
char *s[3];
func(s, SIZE(s));
for (size_t i = 0; i < SIZE(s); i++) {
puts(s[i]);
free(s[i]); // free what you've malloc'ed when you are done with it
}
}
Note that with the use of the macro there is only one hardcoded 3 in the program. Even that could be made into a named constant (#define CHAR_PTRS (3) or enum { CHAR_PTRS = 3 };) to further the ease of reading and maintaining the code.
A non-idiomatic version only accepting a pointer to an array of a fixed (at compile time) size could look like like below. In this example you couldn't accidentally provide a pointer to an array with only 2 char* (which would cause the function to write out of bounds). Instead, it'd result in a compilation error.
#include <stdio.h>
#include <stdlib.h>
// Here `s` is a pointer to an array of 3 char*
void func(char *(*s)[3]) {
for (int i = 0; i < 3; i++) {
(*s)[i] = malloc(10);
if((*s)[i] == NULL) exit(1);
snprintf((*s)[i], 10, "#%d", i);
}
}
int main() {
char *s[3];
func(&s); // &s is a char*(*)[3]
for (int i = 0; i < 3; i++) {
printf("%s\n", s[i]);
free(s[i]);
}
}
#include <stdio.h>
#include <string.h>
void func(char **s){
for(int i=0; i<3; i++){
s[i]=malloc(sizeof(char) * 100);
char buf[10];
snprintf(buf, 10, "#%d",i);
strcpy(s[i], buf);
}
}
int main()
{
char *s[3];
func(s);
for(int i=0; i<3; i++){
printf("%s", s[i]);
}
return 0;
}
This fixed my problem. My understanding is that I assigned memory and then copied the contents of buf to s to the now-present memory.
I know how to create an array of structs but with a predefined size. However is there a way to create a dynamic array of structs such that the array could get bigger?
For example:
typedef struct
{
char *str;
} words;
main()
{
words x[100]; // I do not want to use this, I want to dynamic increase the size of the array as data comes in.
}
Is this possible?
I've researched this: words* array = (words*)malloc(sizeof(words) * 100);
I want to get rid of the 100 and store the data as it comes in. Thus if 76 fields of data comes in, I want to store 76 and not 100. I'm assuming that I don't know how much data is coming into my program. In the struct I defined above I could create the first "index" as:
words* array = (words*)malloc(sizeof(words));
However I want to dynamically add elements to the array after. I hope I described the problem area clearly enough. The major challenge is to dynamically add a second field, at least that is the challenge for the moment.
I've made a little progress however:
typedef struct {
char *str;
} words;
// Allocate first string.
words x = (words) malloc(sizeof(words));
x[0].str = "john";
// Allocate second string.
x=(words*) realloc(x, sizeof(words));
x[1].FirstName = "bob";
// printf second string.
printf("%s", x[1].str); --> This is working, it's printing out bob.
free(x); // Free up memory.
printf("%s", x[1].str); --> Not working since its still printing out BOB even though I freed up memory. What is wrong?
I did some error checking and this is what I found. If after I free up memory for x I add the following:
x=NULL;
then if I try to print x I get an error which is what I want. So is it that the free function is not working, at least on my compiler? I'm using DevC??
Thanks, I understand now due to:
FirstName is a pointer to an array of char which is not being allocated by the malloc, only the pointer is being allocated and after you call free, it doesn't erase the memory, it just marks it as available on the heap to be over written later. – MattSmith
Update
I'm trying to modularize and put the creation of my array of structs in a function but nothing seems to work. I'm trying something very simple and I don't know what else to do. It's along the same lines as before, just another function, loaddata that is loading the data and outside the method I need to do some printing. How can I make it work? My code is as follows:
# include <stdio.h>
# include <stdlib.h>
# include <string.h>
# include <ctype.h>
typedef struct
{
char *str1;
char *str2;
} words;
void LoadData(words *, int *);
main()
{
words *x;
int num;
LoadData(&x, &num);
printf("%s %s", x[0].str1, x[0].str2);
printf("%s %s", x[1].str1, x[1].str2);
getch();
}//
void LoadData(words *x, int * num)
{
x = (words*) malloc(sizeof(words));
x[0].str1 = "johnnie\0";
x[0].str2 = "krapson\0";
x = (words*) realloc(x, sizeof(words)*2);
x[1].str1 = "bob\0";
x[1].str2 = "marley\0";
*num=*num+1;
}//
This simple test code is crashing and I have no idea why. Where is the bug?
You've tagged this as C++ as well as C.
If you're using C++ things are a lot easier. The standard template library has a template called vector which allows you to dynamically build up a list of objects.
#include <stdio.h>
#include <vector>
typedef std::vector<char*> words;
int main(int argc, char** argv) {
words myWords;
myWords.push_back("Hello");
myWords.push_back("World");
words::iterator iter;
for (iter = myWords.begin(); iter != myWords.end(); ++iter) {
printf("%s ", *iter);
}
return 0;
}
If you're using C things are a lot harder, yes malloc, realloc and free are the tools to help you. You might want to consider using a linked list data structure instead. These are generally easier to grow but don't facilitate random access as easily.
#include <stdio.h>
#include <stdlib.h>
typedef struct s_words {
char* str;
struct s_words* next;
} words;
words* create_words(char* word) {
words* newWords = malloc(sizeof(words));
if (NULL != newWords){
newWords->str = word;
newWords->next = NULL;
}
return newWords;
}
void delete_words(words* oldWords) {
if (NULL != oldWords->next) {
delete_words(oldWords->next);
}
free(oldWords);
}
words* add_word(words* wordList, char* word) {
words* newWords = create_words(word);
if (NULL != newWords) {
newWords->next = wordList;
}
return newWords;
}
int main(int argc, char** argv) {
words* myWords = create_words("Hello");
myWords = add_word(myWords, "World");
words* iter;
for (iter = myWords; NULL != iter; iter = iter->next) {
printf("%s ", iter->str);
}
delete_words(myWords);
return 0;
}
Yikes, sorry for the worlds longest answer. So WRT to the "don't want to use a linked list comment":
#include <stdio.h>
#include <stdlib.h>
typedef struct {
char** words;
size_t nWords;
size_t size;
size_t block_size;
} word_list;
word_list* create_word_list(size_t block_size) {
word_list* pWordList = malloc(sizeof(word_list));
if (NULL != pWordList) {
pWordList->nWords = 0;
pWordList->size = block_size;
pWordList->block_size = block_size;
pWordList->words = malloc(sizeof(char*)*block_size);
if (NULL == pWordList->words) {
free(pWordList);
return NULL;
}
}
return pWordList;
}
void delete_word_list(word_list* pWordList) {
free(pWordList->words);
free(pWordList);
}
int add_word_to_word_list(word_list* pWordList, char* word) {
size_t nWords = pWordList->nWords;
if (nWords >= pWordList->size) {
size_t newSize = pWordList->size + pWordList->block_size;
void* newWords = realloc(pWordList->words, sizeof(char*)*newSize);
if (NULL == newWords) {
return 0;
} else {
pWordList->size = newSize;
pWordList->words = (char**)newWords;
}
}
pWordList->words[nWords] = word;
++pWordList->nWords;
return 1;
}
char** word_list_start(word_list* pWordList) {
return pWordList->words;
}
char** word_list_end(word_list* pWordList) {
return &pWordList->words[pWordList->nWords];
}
int main(int argc, char** argv) {
word_list* myWords = create_word_list(2);
add_word_to_word_list(myWords, "Hello");
add_word_to_word_list(myWords, "World");
add_word_to_word_list(myWords, "Goodbye");
char** iter;
for (iter = word_list_start(myWords); iter != word_list_end(myWords); ++iter) {
printf("%s ", *iter);
}
delete_word_list(myWords);
return 0;
}
If you want to dynamically allocate arrays, you can use malloc from stdlib.h.
If you want to allocate an array of 100 elements using your words struct, try the following:
words* array = (words*)malloc(sizeof(words) * 100);
The size of the memory that you want to allocate is passed into malloc and then it will return a pointer of type void (void*). In most cases you'll probably want to cast it to the pointer type you desire, which in this case is words*.
The sizeof keyword is used here to find out the size of the words struct, then that size is multiplied by the number of elements you want to allocate.
Once you are done, be sure to use free() to free up the heap memory you used in order to prevent memory leaks:
free(array);
If you want to change the size of the allocated array, you can try to use realloc as others have mentioned, but keep in mind that if you do many reallocs you may end up fragmenting the memory. If you want to dynamically resize the array in order to keep a low memory footprint for your program, it may be better to not do too many reallocs.
This looks like an academic exercise which unfortunately makes it harder since you can't use C++. Basically you have to manage some of the overhead for the allocation and keep track how much memory has been allocated if you need to resize it later. This is where the C++ standard library shines.
For your example, the following code allocates the memory and later resizes it:
// initial size
int count = 100;
words *testWords = (words*) malloc(count * sizeof(words));
// resize the array
count = 76;
testWords = (words*) realloc(testWords, count* sizeof(words));
Keep in mind, in your example you are just allocating a pointer to a char and you still need to allocate the string itself and more importantly to free it at the end. So this code allocates 100 pointers to char and then resizes it to 76, but does not allocate the strings themselves.
I have a suspicion that you actually want to allocate the number of characters in a string which is very similar to the above, but change word to char.
EDIT: Also keep in mind it makes a lot of sense to create functions to perform common tasks and enforce consistency so you don't copy code everywhere. For example, you might have a) allocate the struct, b) assign values to the struct, and c) free the struct. So you might have:
// Allocate a words struct
words* CreateWords(int size);
// Assign a value
void AssignWord(word* dest, char* str);
// Clear a words structs (and possibly internal storage)
void FreeWords(words* w);
EDIT: As far as resizing the structs, it is identical to resizing the char array. However the difference is if you make the struct array bigger, you should probably initialize the new array items to NULL. Likewise, if you make the struct array smaller, you need to cleanup before removing the items -- that is free items that have been allocated (and only the allocated items) before you resize the struct array. This is the primary reason I suggested creating helper functions to help manage this.
// Resize words (must know original and new size if shrinking
// if you need to free internal storage first)
void ResizeWords(words* w, size_t oldsize, size_t newsize);
In C++, use a vector. It's like an array but you can easily add and remove elements and it will take care of allocating and deallocating memory for you.
I know the title of the question says C, but you tagged your question with C and C++...
Another option for you is a linked list. You'll need to analyze how your program will use the data structure, if you don't need random access it could be faster than reallocating.
Your code in the last update should not compile, much less run. You're passing &x to LoadData. &x has the type of **words, but LoadData expects words* . Of course it crashes when you call realloc on a pointer that's pointing into stack.
The way to fix it is to change LoadData to accept words** . Thi sway, you can actually modify the pointer in main(). For example, realloc call would look like
*x = (words*) realloc(*x, sizeof(words)*2);
It's the same principlae as in "num" being int* rather than int.
Besides this, you need to really figure out how the strings in words ere stored. Assigning a const string to char * (as in str2 = "marley\0") is permitted, but it's rarely the right solution, even in C.
Another point: non need to have "marley\0" unless you really need two 0s at the end of string. Compiler adds 0 tho the end of every string literal.
For the test code: if you want to modify a pointer in a function, you should pass a "pointer to pointer" to the function. Corrected code is as follows:
#include <stdio.h>
#include <stdlib.h>
#include <ctype.h>
typedef struct
{
char *str1;
char *str2;
} words;
void LoadData(words**, int*);
main()
{
words **x;
int num;
LoadData(x, &num);
printf("%s %s\n", (*x[0]).str1, (*x[0]).str2);
printf("%s %s\n", (*x[1]).str1, (*x[1]).str2);
}
void LoadData(words **x, int *num)
{
*x = (words*) malloc(sizeof(words));
(*x[0]).str1 = "johnnie\0";
(*x[0]).str2 = "krapson\0";
*x = (words*) realloc(*x, sizeof(words) * 2);
(*x[1]).str1 = "bob\0";
(*x[1]).str2 = "marley\0";
*num = *num + 1;
}
Every coder need to simplify their code to make it easily understood....even for beginners.
So array of structures using dynamically is easy, if you understand the concepts.
// Dynamically sized array of structures
#include <stdio.h>
#include <stdlib.h>
struct book
{
char name[20];
int p;
}; //Declaring book structure
int main ()
{
int n, i;
struct book *b; // Initializing pointer to a structure
scanf ("%d\n", &n);
b = (struct book *) calloc (n, sizeof (struct book)); //Creating memory for array of structures dynamically
for (i = 0; i < n; i++)
{
scanf ("%s %d\n", (b + i)->name, &(b + i)->p); //Getting values for array of structures (no error check)
}
for (i = 0; i < n; i++)
{
printf ("%s %d\t", (b + i)->name, (b + i)->p); //Printing values in array of structures
}
scanf ("%d\n", &n); //Get array size to re-allocate
b = (struct book *) realloc (b, n * sizeof (struct book)); //change the size of an array using realloc function
printf ("\n");
for (i = 0; i < n; i++)
{
printf ("%s %d\t", (b + i)->name, (b + i)->p); //Printing values in array of structures
}
return 0;
}
If you want to grow the array dynamically, you should use malloc() to dynamically allocate some fixed amount of memory, and then use realloc() whenever you run out. A common technique is to use an exponential growth function such that you allocate some small fixed amount and then make the array grow by duplicating the allocated amount.
Some example code would be:
size = 64; i = 0;
x = malloc(sizeof(words)*size); /* enough space for 64 words */
while (read_words()) {
if (++i > size) {
size *= 2;
x = realloc(sizeof(words) * size);
}
}
/* done with x */
free(x);
Here is how I would do it in C++
size_t size = 500;
char* dynamicAllocatedString = new char[ size ];
Use same principal for any struct or c++ class.
I have the following C code which works:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <malloc.h>
int pw = sizeof(char*); // width of pointer (to char)
int num;
int first = 1;
int size = 0;
int incr = 10;
char *(*arr)[]; // pointer to array of pointers to char */
test(char* s, int i)
{
int j;
char *(*newarr)[]; // pointer to array of pointers to char
if (first) { // first time
arr = malloc(pw*incr); // malloc array
first = 0; // skip from now on
size = incr; // save the size
}
if (i >= size) { // out of space
newarr = malloc(pw*(size+incr)); // get incr bigger space
for (j=0; j<size; j++) // copy the elements from the old
(*newarr)[j] = (*arr)[j]; // array to new array
free(arr); // free the old array space
arr = newarr; // point old array to new array
size = size+incr;
};
int len = strlen(s); // length of s
(*arr)[i] = malloc(len+1); // assign pointer to pointer array element
strcpy((*arr)[i], s); // copy s to array
// both arguments must be pointers
printf("%d\t%s\n", i, (*arr)[i]);
};
main()
{
char* s = "this is a string";
for (num=0; num<30; num++) // add 30 pointers to s to *arr
test(s, num);
for (num=0; num<30; num++)
printf("%d\t%s\n", num, (*arr)[num]); // print out what they point to
};
It prints out 'i\tthis is a string' for 'i' from 0 to 29 twice. What I want to do is pass 'arr' from the top of the file as an argument of 'test'. The reason I want to do that is because I want to pass several different arrays all of which are declared the same way. If I make the minimal changes to do that I get:
0 this is a string
Segmentation fault (core dumped)
Here is the output of the diff command which shows the minimal changes:
13c13
< char *(*arr)[]; // pointer to array of pointers to char */
---
> char *(*jarr)[]; // pointer to array of pointers to char */
15c15
< test(char* s, int i)
---
> test(char* s, int i, char *(*arr)[])
52c52
< test(s, num);
---
> test(s, num, jarr);
54,55d53
< for (num=0; num<30; num++)
< printf("%d\t%s\n", num, (*arr)[num]); // print out what they point to
In other words everything is the same except for renaming 'arr' as 'jarr' and passing it to 'test'.
Thanks in advance,
Mike
The trouble occurs when you call:
test(s, num, jarr);
You are passing jarr by value. Inside the function, you are reallocating (the hard way — why not use realloc() which does the copying for you?) the array, but that change does not affect the value of jarr 'in main()' because it was passed by value. The second time through the loop, you are still passing a null pointer to the function, but you are then dereferencing that null pointer, which is bad news.
How to fix?
Fair question...I'm not sure if the old "well, if I want to get to there, I wouldn't start from here" gag passes muster.
The 'simplest' change is to revise the call:
jarr = test(s, num, jarr);
and then 'just' revise the function so that it returns a pointer to an array of character pointers. That is a very esoteric function. My brain's not awake (insufficient caffeine), so I used an intermediate typedef to get around the problem of how to write the function declaration and definition:
typedef char *(ArrayString[]);
ArrayString *test3(char *s, int i, char *(*arr)[]);
ArrayString *test3(char *s, int i, char *(*arr)[]) { (*arr)[i] = s; return arr; }
It compiles without warnings; that isn't a guarantee that it's correct.
The primary alternative is to pass a pointer to a pointer to an array of char pointers to the function, which is even more esoteric.
However, both of these are 'starting from here' solutions. You'd do better, on the whole, to devise a different way of handling things. Pointers to arrays are certainly a part of C, but they are at the outer edges of C and you should generally assume that if your design calls for their use, then your design is probably not the best. You should use a simpler char ** (or, perish the thought, char ***; triple indirection is best avoided too, but that isn't always possible).
You seem to have misunderstood how arrays and pointers works. Lets say you want a dynamic array of strings, that is basically a pointer to a pointer of char:
char **arr = NULL;
To allocate memory for that you do e.g.
arr = malloc(sizeof(char *) * current_size);
Now you have an "array" of character pointers. Lets say you want each of these to be a specific string str:
for (int i = 0; i < current_size; i++)
{
arr[i] = strdup(str);
}
Oh, now you need to increase the number of strings, all initialized to the same string as before:
size_t new_size = current_size + 10;
arr = realloc(arr, sizeof(char *) * new_size);
for (int i = current_size; i < new_size)
{
arr[i] = strdup(str);
}
The problem now is that you want to do all of the above in a separate function. It's first now that you have to add another indirection.
I think you can do a double check on the first malloc value assigned to jarr both in the test(s, 0, jarr) and out of the test(s, 0, jarr); the jarr assignement is not successful since you change the pointer value in the passing by value.
I need to make an array of strings for a program in one of my CS classes. We are to just assume that the length of all the strings is no more than 50 (this accounts for the null character).
I need use malloc() or calloc() to allocate the proper amount of memory for the array, but I am new to C and I don't really know how to use those functions.
The real question I guess is how much memory to I need do allocate for an array of x strings of 50 characters.
Assuming type char, at minimum you will need X * sizeof(char) * 50.
If you are doing all of these allocations separately, there will be overhead for each allocation. So the total amount of memory in this case will be higher.
This overhead is unspecified and can be fairly large.
But I wouldn't worry about that for a homework assignment. I can't imagine the problem needing enough memory to possibly run your system out.
\0 is called the termination character for strings.
What you need is array of char pointers.
char *strArrayPtr[X]; // X needs to be a compile time constant.
// C99 supports variable length arrays too.
Now each index holds pointer to an array that is allocated by malloc(50);
Example:
#include <stdlib.h>
#include <stdio.h>
int main() {
char *ar[2] ;
ar[0] = "Hello"; // This needs to malloced memory in your case
ar[1] = "World!"; // i.e., ar[0] = malloc(50);
printf("%s", ar[0]);
return 0;
}
If you want to make a variable-sized array of fixed-size strings:
char **arr = calloc(len, 50 * sizeof(char));
Don't forget to free the memory!
for(unsigned long i = 0; i < len; ++i)
free(*arr++);
You're not going to be dynamically pushing elements, are you? If so, we're going to have to get a bit more complicated. (I'd add a StringArray::capacity, to speed up push, but I don't want to overcomplicate things... Seeing as how I suck at C, if you look at the comments below. ;))
struct StringArray
{
char** arr;
unsigned long len = 0;
};
StringArray StringArray_init(char** arr = NULL, unsigned long len = NULL)
{
StringArray a;
a.arr = arr;
a.len = len;
return(a);
}
void StringArray_push(StringArray *a, char* str)
{
if(len == 0)
{
a.arr = StringArrayInit(malloc(sizeof(char*)), 1);
}
else
{
a.len++;
}
a.arr = realloc(a.arr, a.len * sizeof(char*));
a.arr[a.len - 1] = malloc((strlen(str) + 1) * sizeof(char));
strcpy(a.arr[a.len - 1], str);
}
void StringArray_free(StringArray a)
{
for(unsigned long i = 0; i < a.len; ++i)
free(a.arr[i]);
}
StringArray szArr = StringArray_init();
StringArray_push(&szArr, "This is a string.");
StringArray_free(szArr);
It's a heck lot easier with C++. :)
std::vector<std::string> arr;
arr.push_back("This is a string.");
char * myFunction () {
char sub_str[10][20];
return sub_str;
}
void main () {
char *str;
str = myFunction();
}
error:return from incompatible pointer type
thanks
A string array in C can be used either with char** or with char*[]. However, you cannot return values stored on the stack, as in your function. If you want to return the string array, you have to reserve it dynamically:
char** myFunction() {
char ** sub_str = malloc(10 * sizeof(char*));
for (int i =0 ; i < 10; ++i)
sub_str[i] = malloc(20 * sizeof(char));
/* Fill the sub_str strings */
return sub_str;
}
Then, main can get the string array like this:
char** str = myFunction();
printf("%s", str[0]); /* Prints the first string. */
EDIT: Since we allocated sub_str, we now return a memory address that can be accessed in the main
To programmers just starting out, the concept of a "stack" or the "heap" might be a little confusing, especially if you have started programming in a higher level language like Ruby, Java, Python, etc.
Consider:
char **get_me_some_strings() {
char *ary[] = {"ABC", "BCD", NULL};
return ary;
}
The compiler will rightfully issue a complaint about trying to return address of a local variable, and you will most certainly get a segmentation fault trying to use the returned pointer.
and:
char **get_me_some_strings() {
char *ary[] = {"ABC", "BCD", NULL};
char **strings = ary;
return strings;
}
will shut the compiler up, while still getting the same nasty segmentation fault.
To keep everyone but the zealots happy, you would do something a little more elaborate:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
char **get_me_some_strings() {
char *ary[] = { "ABC", "BCD", NULL };
char **strings = ary; // a pointer to a pointer, for easy iteration
char **to_be_returned = malloc(sizeof(char*) * 3);
int i = 0;
while(*strings) {
to_be_returned[i] = malloc( sizeof(char) * strlen( *strings ) );
strcpy( to_be_returned[i++], *strings);
strings++;
}
return to_be_returned;
}
now use it:
void i_need_me_some_strings() {
char **strings = get_me_some_strings();
while(*strings) {
printf("a fine string that says: %s", *strings);
strings++;
}
}
Just remember to free the allocated memory when you are done, cuz nobody will do it for you. That goes for all the pointers, not just the pointer to the pointers! (i think).
To make more sense of it all, you might also want to read this: What and where are the stack and heap?
Reason:
you need the return type to be char(*)[20]. But even in this case you don't want to return a pointer to a local object from the function.
Do:
Use malloc to allocate sub_str, and return char**.
The cause of your compiler error is simple, but not the answer to what you really want to do. You are declaring that the function returns a char *, while returning a char **.
Without knowing the details of what you're doing, I'm going to assume one of two things are true:
1) The purpose of the function is to create and return an array of strings.
2) The function performs some operation(s) on an array of strings.
If #1 is true, you need several malloc calls to make this work (It can really be done with only two, but for purposes of simplicity, I'll use several).
If you don't know how large the array is supposed to be, your function declaration should look like this:
char ** allocateStrings ( int numberOfStrings, int strLength );
The reason for this is because you're essentially returning a pointer to an array of pointers and you need to know how many strings and how long each string is.
char ** allocateStrings ( int numberOfStrings, int strLength )
{
int i;
//The first line is allocating an array of pointers to chars, not actually allocating any strings itself
char ** retVal = ( char ** ) malloc ( sizeof ( char * ) * numberOfStrings );
//For each string, we need to malloc strLength chars
for ( i = 0; i < numberOfStrings; i ++ )
{
//Allocate one extra char for the null pointer at the end
retVal [ i ] = ( char * ) malloc ( sizeof ( char ) * ( strLength + 1 ) );
}
return retVal;
}
As somebody else pointed out, it's best practice to have whatever does the allocating also do the deallocating. So a cleanup function is needed.
void cleanupStrings ( char ** strArray, int numberOfStrings )
{
int i;
for ( i = 0; i < numberOfStrings; i ++ )
{
//Should be checking to see if this is a null pointer.
free ( strArray [ i ] );
}
//Once the strings themselves are freed, free the actual array itself.
free ( strArray );
}
Now, keep in mind that once the cleanup function is called, you no longer have access to the array. Trying to still use it will most likely cause your application to crash.
If #2 is true, then you want to allocate the strings, process the strings, and clean them up. You should use the two functions above to allocate/deallocate your strings, then a third function to do whatever with them.
void processStrings ( char ** strArray, int numberOfStrings, int strLength );
As others have said, you cannot return a local char array to the caller, and have to use heap memory for this.
However, I would not advise using malloc() within the function.
Good practice is that, whoever allocates memory, also deallocates it (and handles the error condition if malloc() returns NULL).
Since your myFunction() does not have control over the memory it allocated once it returned, have the caller provide the memory in which to store the result, and pass a pointer to that memory.
That way, the caller of your function can de-allocate or re-use the memory (e.g. for subsequent calls to myFunction()) however he sees fit.
Be careful, though, to either agree on a fixed size for such calls (through a global constant), or to pass the maximum size as additional parameter, lest you end up overwriting buffer limits.
As others correctly said you should use dynamic memory allocation by malloc to store your array inside heap and return a pointer to its first element.
Also I find it useful to write a simple array of string implementation which has a minimal API for data manipulation.
Type and API:
typedef struct {
char **array_ptr;
int array_len;
int string_len;
} array_t;
array_t* array_string_new(int array_len, int string_len);
int array_string_set(array_t *array, int index, char *string);
char* array_string_get(array_t *array, int index);
int array_string_len(array_t *array);
Usage:
It creates an array with 4 dimensions that can store strings with 4 characters length. If the string length goes beyond the specified length, just its first 4 characters will be stored.
int main()
{
int i;
array_t *array = array_string_new(4, 4);
array_string_set(array, 0, "foo");
array_string_set(array, 1, "bar");
array_string_set(array, 2, "bat");
array_string_set(array, 3, ".... overflowed string");
for(i = 0; i < array_string_len(array); i++)
printf("index: %d - value: %s\n", i, array_string_get(array, i));
/* output:
index: 0 - value: foo
index: 1 - value: bar
index: 2 - value: bat
index: 3 - value: ...
*/
array_string_free(array);
return 0;
}
Implementation:
array_t*
array_string_new(int array_len, int string_len)
{
int i;
char **array_ptr = (char**) malloc(array_len * sizeof(char**));
for(i = 0; i < array_len; i++) {
array_ptr[i] = (char*) malloc(string_len * sizeof(char));
}
array_t *array = (array_t*) malloc(sizeof(array_t*));
array->array_ptr = array_ptr;
array->array_len = array_len;
array->string_len = string_len;
return array;
}
int
array_string_set(array_t *array, int index, char *string)
{
strncpy(array->array_ptr[index], string, array->string_len);
return 0;
}
char*
array_string_get(array_t *array, int index)
{
return array->array_ptr[index];
}
int
array_string_len(array_t *array)
{
return array->array_len;
}
int
array_string_free(array_t *array)
{
int i;
for(i = 0; i < array->array_len; i++) {
free(array->array_ptr[i]);
}
free(array->array_ptr);
return 0;
}
Notice that it is just a simple implementation with no error checking.
i use that function to split a string to string array
char ** split(char *str, char *delimiter)
{
char *temp=strtok(str,delimiter);
char *arr[]={temp};
int i=0;
while(true)
{
elm=strtok (NULL, delimiter);
if(!temp) break;
arr[++i]=temp;
}
return arr;
}
first of all You can not return a string variable which is stored in stack you need use malloc to allocate memory dynamicaly here is given datails with the example
Go https://nxtspace.blogspot.com/2018/09/return-array-of-string-and-taking-in-c.html
get a proper answer
char *f()
{
static char str[10][20];
// ......
return (char *)str;
}
int main()
{
char *str;
str = f();
printf( "%s\n", str );
return 0;
}
You can use static instead of malloc. It's your choice.