how can i fix the function a3 to obtain my output - arrays

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
char null;
static char a3[](char a[], int start, int length)
{
if(length < 0 || start < 0 || start + length -1 >= sizeof(a))
{
return null;
}
char sub[] = new char[length];
for (int i=start, j=0; j<length; i++, j++)
{
sub[j] = a[i];
}
return sub;
}
int main()
{
char a[]= {'a', 'b','c'};
int start = 0;
int length = 3;
printf("%d\n", a3(a, start,length));
return 0;
}
I want to write a function that accepts a character array, a zero-based start position, and a length. It should return a character array containing length characters starting with the start character of the input array. The function should do error checking on the start position and the length and return null if either value is not legal. when I build it gives me the following error " error: expected '=', ',', ';', 'asm' or 'attribute' before '{' token|". I don't know how to fix this error. Can anyone help me ??

Values of array type cannot be passed to functions, returned from functions, or assign to an object of array type. However, a pointer to an element of an array can be passed to a function or returned from a function. Therefore, the prototype of function a3 should be something like:
static char *a3(char a[], int start, int length)
A function parameter of array type is automatically adjusted to have pointer type and will point to the first element of the array. Therefore the above prototype is equivalent to:
static char *a3(char *a, int start, int length)
The function cannot determine the size of the array because the array parameter is actually just a pointer. The expression sizeof(a) in function a3 is equivalent to sizeof(char *) and is unrelated to the length of the array. The function will need to be told the length of the array in some other way, perhaps with another parameter:
static char *a3(char *a, int a_len, int start, int length)
Then the code to test for correct parameters can be something like:
if (length < 0 || start < 0 || start + length > a_len)
{
return NULL;
}
Note that NULL is a null pointer constant and the returned value will be a null pointer value of type char *. This is preferable to the existing code that converts the value of the variable null to a char * without a cast.
If you create an array or other variable with automatic storage class in a function or block, it ceases to exist when the end of the function or block is reached. Therefore, if the function returns a pointer to such a variable, the pointer will be invalid. The caller cannot use it to access the contents of the variable, since it no longer exists. Therefore, the function should use the memory management functions such as malloc or calloc to allocate storage for the object and return a pointer to that storage. The storage persists at the address until free is called to free the storage, or realloc is called to change its size.
The existing code uses the C++ new operator to create the storage for array sub, but that is not supported by C. The C equivalent is to declare sub as a pointer and use malloc or calloc to allocate the storage. (calloc also sets all bytes of the returned memory block to 0.):
char *sub = malloc(length * sizeof(char));
or:
char *sub = calloc(length, sizeof(char));
Note that sizeof(char) is 1 by definition, so the above can be simplified to:
char *sub = malloc(length);
or:
char *sub = calloc(length, 1);
It is possible for malloc or calloc to fail to allocate the memory (unlikely for small programs allocating small amounts of memory), in which case they return a null pointer. The function should check for that and return an error:
if (sub == NULL)
{
return NULL;
}
There is an error in main where it is using the printf %d specifier to print the return value of a3(). The %d specifier expects a value of type int (after default argument promotions), so I do not know what OP expects to print there.
Putting it all together and changing the main function to print something sensible, we have the following:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
static char *a3(char a[], int a_len, int start, int length)
{
if(length < 0 || start < 0 || start + length > a_len)
{
return NULL;
}
char *sub = malloc(length);
if (sub == NULL)
{
return NULL;
}
for (int i=start, j=0; j<length; i++, j++)
{
sub[j] = a[i];
}
return sub;
}
int main(void)
{
char a[]= {'a', 'b','c'};
int a_len = 3;
int start = 0;
int length = 3;
char *sub = a3(a, a_len, start, length);
if (sub == NULL)
{
printf("Error\n");
exit(EXIT_FAILURE);
}
for (int i = 0; i < length; i++)
{
printf("%c", sub[i]);
}
printf("\n");
free(sub); // free the storage returned by a3()
return 0;
}
There are various improvements that could be made. For example, the a parameter of a3 can be changed to const char *a (or const char a[] since that will be adjusted to const char *a) to indicate that it does not modify the contents pointed to by a.

Related

Don't know how to implement pointer to array of pointers to char

I'm not great with pointers. I know enough to get an array of pointers to char to work, as in the first example below. But I don't want to pass an entire array of pointers, because it takes up too much room on the stack. What I would like to do is pass a single pointer to the memory allocated for the array of pointers. I have no idea how to do this.
This program works:
#include "pch.h"
#include "$StdHdr.h"
#include "TmpTstPtr1.h"
#define SRC_LIN_SIZ 150
int main(int ArgCnt, char * ArgVal[])
{
char InpFilPth[MAX_PATH + 1];
FILE * InpFilPtr;
char ** SrcArr;
unsigned Sub1;
unsigned SrcArrCnt = 0;
strncpy_s(InpFilPth, "TmpTstPtr1.cpp", strlen("TmpTstPtr1.cpp"));
fopen_s(&InpFilPtr, InpFilPth, "r");
SrcArr = (char **)malloc(999999 * sizeof(char *));
LodSrcArr(InpFilPtr, SrcArr, &SrcArrCnt);
for (Sub1 = 0; Sub1 < SrcArrCnt; Sub1++) {
printf("SrcArr[%d] = %s\n", Sub1, SrcArr[Sub1]);
}
fclose(InpFilPtr);
return 0;
}
void LodSrcArr(FILE * InpFilPtr, char ** SrcArr, unsigned * SrcArrCnt)
{
char SrcLin[SRC_LIN_SIZ + 1];
char * GetStrPtr;
GetStrPtr = GetStr(SrcLin, SRC_LIN_SIZ, InpFilPtr);
while (GetStrPtr != NULL) {
SrcArr[*SrcArrCnt] = (char *)malloc(SRC_LIN_SIZ + 1);
// CpySiz(SrcArr[*SrcArrCnt], strlen(SrcLin) + 1, SrcLin);
errno = strncpy_s(SrcArr[*SrcArrCnt], SRC_LIN_SIZ + 1, SrcLin, strlen(SrcLin));
(*SrcArrCnt)++;
GetStrPtr = GetStr(SrcLin, SRC_LIN_SIZ, InpFilPtr);
}
}
char * GetStr(char * Str, const int MaxChr, FILE * InpFilPtr)
{
char * InpRtnVal = NULL;
unsigned Sub1;
// Get string from input file. Find the end of the string if something entered.
InpRtnVal = fgets(Str, MaxChr + 1, InpFilPtr);
if (InpRtnVal != NULL) {
Sub1 = 0;
while (Str[Sub1] != '\n' && Str[Sub1] != '\0') {
Sub1++;
}
// Replace newline with null.
if (Str[Sub1] == '\n') {
Str[Sub1] = '\0';
}
}
return InpRtnVal;
The following program doesn't even come close:
#include "pch.h"
#include "$StdHdr.h"
#include "TmpTstPtr2.h"
#define SRC_LIN_SIZ 150
int main(int ArgCnt, char * ArgVal[])
{
char InpFilPth[MAX_PATH + 1];
FILE * InpFilPtr;
char ** SrcArr;
unsigned Sub1;
unsigned SrcArrCnt = 0;
char *** SrcArrPtr = NULL;
strncpy_s(InpFilPth, "TmpTstPtr2.cpp", strlen("TmpTstPtr2.cpp"));
fopen_s(&InpFilPtr, InpFilPth, "r");
SrcArr = (char **)malloc(999999 * sizeof(char *));
SrcArrPtr = &SrcArr;
LodSrcArr(InpFilPtr, SrcArrPtr, &SrcArrCnt);
SrcArrPtr = &SrcArr;
for (Sub1 = 0; Sub1 < SrcArrCnt; Sub1++) {
// printf("SrcArr[%d] = %s\n", Sub1, SrcArr[Sub1]); // got "Exception thrown: read access violation. it was 0xCDCDCDCD."
printf("SrcArr[%d] = %s\n", Sub1, **SrcArrPtr); // get 75 lines of garbage
(**SrcArrPtr) += sizeof(char *);
}
fclose(InpFilPtr);
return 0;
}
void LodSrcArr(FILE * InpFilPtr, char *** SrcArrPtr, unsigned * SrcArrCnt)
{
char SrcLin[SRC_LIN_SIZ + 1];
char * GetStrPtr;
GetStrPtr = GetStr(SrcLin, SRC_LIN_SIZ, InpFilPtr);
// while (GetStrPtr != NULL and *SrcArrCnt == 0) {
while (GetStrPtr != NULL) {
**SrcArrPtr = (char *)malloc(SRC_LIN_SIZ + 1);
// CpySiz(SrcArr[*SrcArrCnt], strlen(SrcLin) + 1, SrcLin);
errno = strncpy_s(**SrcArrPtr, SRC_LIN_SIZ + 1, SrcLin, strlen(SrcLin));
(**SrcArrPtr) += sizeof(char *);
(*SrcArrCnt)++;
GetStrPtr = GetStr(SrcLin, SRC_LIN_SIZ, InpFilPtr);
}
}
char * GetStr(char * Str, const int MaxChr, FILE * InpFilPtr)
{
char * InpRtnVal = NULL;
unsigned Sub1;
// Get string from input file. Find the end of the string if something entered.
InpRtnVal = fgets(Str, MaxChr + 1, InpFilPtr);
if (InpRtnVal != NULL) {
Sub1 = 0;
while (Str[Sub1] != '\n' && Str[Sub1] != '\0') {
Sub1++;
}
// Replace newline with null.
if (Str[Sub1] == '\n') {
Str[Sub1] = '\0';
}
}
return InpRtnVal;
}
As the comments say, when I try to access SrcArr via a subscript, I get a run-time error. When I try to access via the pointer, I get garbage. The problem may be where I say SrcArrPtr = &SrcArr;. I don't know if it's significant, but the garbage printed is 4 characters shorter with each subsequent line. As if it's actually printing the array of pointers itself, rather than the strings they point to. I dunno.
The reason I coded it as above is in order to get the program to compile. I've never tried to use 3 pointers before. Is what I'm trying to do even possible? If so, can someone show me how? An explanation of how it works would be nice, but not necessary. (I'm using Visual Studio 2017, though I don't think it matters.)
TIA.
#include <stddef.h>
#include <stdlib.h>
#include <stdio.h>
void foo(char* bar[10]) { // a real array
for (int i = 0; i < 10; ++i) {
bar[i] = calloc(2, 1);
bar[i][0] = '0' + i;
}
}
void xox(char **qux) { // pointer to some char-pointers on the heap
for (int i = 0; i < 10; ++i) {
qux[i] = calloc(2, 1);
qux[i][0] = '0' + i;
}
}
int main(void)
{
char* bar[10]; // a "real" array
foo(bar);
for (size_t i = 0; i < 10; ++i)
puts(bar[i]);
putchar('\n');
// cleanup:
for (size_t i = 0; i < 10; ++i)
free(bar[i]);
// plan b:
char **qux = calloc(10, sizeof(*qux));
xox(qux);
for (size_t i = 0; i < 10; ++i)
puts(qux[i]);
putchar('\n');
// cleanup:
for (size_t i = 0; i < 10; ++i)
free(qux[i]);
free(qux);
}
What I would like to do is pass a single pointer to the memory
allocated for the array of pointers.
Suppose you have some integers on the heap, like this:
int *integers = (int*)malloc(4 * sizeof(int));
And now suppose you have some pointers, also on the heap:
int **pointers = (int**)malloc(4*sizeof(int*));
Now let's assign the pointers to the addresses of the integers:
pointers[0] = &integers[0];
pointers[1] = &integers[1];
pointers[2] = &integers[2];
pointers[3] = &integers[3];
In this example, pointers is a pointer to an array of pointers (on the heap) pointing to some integers (also on the heap). You can freely pass pointers around and use it in another function.
Or, if you wanted the array of pointer to be on the stack:
int* pointers[4];
pointers[0] = &integers[0];
pointers[1] = &integers[1];
pointers[2] = &integers[2];
pointers[3] = &integers[3];
int **ppointer = pointers;
Now ppointer is also a pointer pointing to an array of pointers that point to some integers on the heap. Just notice that this time, those pointers are on the stack, not on the heap. So if you return from this function, they're out of scope and you may not access them anymore.
You're operating under a misconception. Neither C nor C++ pass a copy of an array to a function, nor can they return an array from a function.
Except when it is the operand of the sizeof or unary & operators, or is a string literal used to initialize a character array in a declaration, an expression of type "N-element array of T" will be converted ("decay") to an expression of type "pointer to T", and the value of the expression is the address of the first element.
Thus, if you declare an array like
char *ptrs[N];
and pass it to a function as
foo( ptrs );
the expression ptrs is implicitly converted from "N-element array of char *" to "pointer to char *", and what foo actually receives is a pointer to the first element of the array - it's effectively the same as writing
foo( &ptrs[0] );
The prototype can be written as either
void foo( char **ptrs )
or
void foo( char *ptrs[] )
or
void foo( char *ptrs[N] )
In a function parameter declaration, array declarators are "adjusted" to be pointer declarators - IOW, T a[N] and T a[] are both interpreted to mean T *a. This is only true in a function parameter declaration, though.
As a matter of style...
In C, the cast on malloc is unnecessary1, and under C89 it can suppress a useful diagnostic if you forget to include stdlib.h or otherwise don't have a declaration for malloc (or calloc or realloc) in scope. Under C99 and later, you'll get a diagnostic for not having a declaration, but C89 still allowed implicit int declarations, and the cast will prevent the compiler from yelling at you because int and pointer types are not compatible. I bring this up because MS's support for C past C89 is a bit spotty.
To minimize your maintenance burden, it's better to avoid explicitly naming types in a malloc call. You can rewrite
SrcArr = (char **)malloc(999999 * sizeof(char *));
as
SrcArr = malloc( 999999 * sizeof *SrcArr ); // you sure you need that many elements??!
Since SrcArr has type char **, the expression *SrcArr has type char *, so sizeof *SrcArr is the same as sizeof (char **). In general, a malloc call can be written
T *p = malloc( N * sizeof *p );
or
T *p;
...
p = malloc( N * sizeof *p );
The same is true for calloc and realloc.
This is not the cast in C++, since C++ doesn't allow implicit conversion from void * to other pointer types, but if you're writing C++ you shouldn't be using malloc anyway.

memcpy in a different function having a pointer to pointer argument

I have a following function process calling a routine dataFileBuffer which takes a pointer to a pointer and does a memcpy on the dereferenced pointer location.
int dataFileBuffer(uint8_t *index, char **tempBuf,int size)
{
if(index != stop_address)) /*stop_address is a fixed pointer to the end buffer*/
{
if(*tempBuf)
{
if(index + size < stop_address)
memcpy(*tempBuf,index,size);
else
{
size = stop_address-index-1;
memcpy(*tempBuf,index,size);
}
}
else
size = 0;
}
else
size = 0;
return size;
}
int process()
{
char *readBuf=NULL;
char *tBuf = (char *)malloc(MAX_LENGTH);
int readBytes = -1;
uint8_t *index = start_address;
uint8_t *complete = stop_address;
do
{
readBuf = tBuf+(sizeof(char)*40);
readBytes = 0;
readBytes = dataFileBuffer(index,&readBuf,MAX_LENGTH);
if(readBytes > 0)
{
index = index+readBytes;
}
}while(index <= complete);
return readBytes;
}
My process function is intermittently seeing stack corruptions which is making me think that something is wrong with my implementation of copy.
I just wanted to understand if we can pass a pointer to a pointer as an argument and safely memcpy to the dereferenced location in the called function ?
There are several things wrong with the question's code. Apart from some syntax errors, there is notably the function
dataFileBuffer(index, char **tempBuf,int size)
which does not compile for two reasons, there is no type declared for the argument index, and there is no return value declared - note that the function ends with
return size;
and is called like this:
readBytes = dataFileBuffer(index,&readBuf,MAX_LEN);
and my guess is that it should be
int dataFileBuffer(char *index, char **tempBuf, int size)
but I am puzzled why you have reversed the arguments given to dataFileBuffer() for the memcpy().
Next, you have used MAX_LEN, MAX_LENGTH and 40 to define buffers sizes or offsets, but there is no clear definition or checking as to the size of the available buffer index that you copy into - or is that from :-). It is more usual to offer a buffer size than a pointer limit.
You also have
...
readBytes = dataFileBuffer(index,&readBuf,MAX_LEN);
if(readBytes > 0)
{
index = index+readBytes;
}
} while(index <= complete);
which is likely to cause an infinite loop when readBytes == 0, and anyway will copy the same data on subsequent loops.
Sorry I can't offer a proper solution, as it's all a confused mess.
Added after OP comment
In reply to the specific question about deferencing a **pointer, this example succeeds in doing that, by finding the string length.
#include <stdio.h>
#include <string.h>
// return the length of the string
size_t slen(char **tempBuf)
{
return strlen (*tempBuf);
}
int main(void) {
char string[] = "abcde";
char *sptr = string;
printf ("Length of '%s' is %d\n", string, slen (&sptr));
return 0;
}
Program output:
Length of 'abcde' is 5

Storing chars into a string with a for loop?

I have this function, bits_show, which prints to stdout a 2-3 bit long code.
void bits_show(bits *a)
{
int i;
for (i = 0; i < a->next; i++)
putchar(a->bits[i]);
}
where bits:
struct bits {
int capacity;
int next;
char *bits;
};
I am trying to write a function, char* bits_char(bits a) that captures these characters and collects them into a single char file.
This is what I have so far, but it keeps spitting errors:
char* bits_char(bits *a)
{
char* str = (char*) malloc( sizeof(a->next * char));
int i;
for (i=0; i<a->next; i++){
str[i] = (a->bits[i]);
}
return str;
}
"bits.c: In function ‘bits_char’:
bits.c:33: error: variable-sized object may not be initialized
bits.c:37: warning: function returns address of local variable"
This is wrong:
sizeof(a->next * char)
I presume you meant to write:
a->next * sizeof(char)
But since sizeof(char) equals 1 by definition you would simply omit that.
But even that is wrong since you need to allow space for the null terminator which your code does not currently write. The allocation needs to be:
malloc(a->next+1)
And add the null-terminator like this:
str[a->next] = 0;
All in all, the finished product is as so:
char* bits_char(bits *a)
{
char* str = malloc(a->next+1);
int i;
for (i=0; i<a->next; i++){
str[i] = (a->bits[i]);
}
str[a->next] = 0;
return str;
}
I removed the cast of the return value of malloc which is not needed in C.
And you should also ensure that you check the return value of malloc for a failed allocation. It will return the null pointer if it fails. I've not shown how to do that because I don't know your error handling policy.

how to pass pointer to array of pointers in C

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.

how to return a string array from a function

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.

Resources