I have this function that takes in a string and splits it into words, then store the words into a 2D array, but I am having trouble returning the 2d array. Error: return makes pointer from interger without cast.
char *split_message(char *message)
{
int indexCtr = 0;
int wordIndex = 0;
int totalWords = 0;
int i,rows=0;
int columns= strlen(message);
for(i=0; i<strlen(message);i )
{
if(message[i]==' ');
{
rows ;
}
}
char sentence_split[rows][columns];
for(indexCtr=0;indexCtr<=strlen(message);indexCtr )
{
if(message[indexCtr]==' '||message[indexCtr]=='\0')
{
sentence_split[totalWords][wordIndex]='\0';
totalWords ;
wordIndex=0;
}
else
{
sentence_split[totalWords][wordIndex] = message[indexCtr];
wordIndex ;
}
}
return sentence_split[rows][columns];
}
CodePudding user response:
In general if you want to return an object of a certain type that has not yet been created (i.e. passed in as an argument) it will have to be created in the called function. In your prototype:
char *split_message(char *message)
{
char sentence_split[rows][columns];
...
return sentence_split[rows][columns];
}
the code expects to return a char *
, but it is actually attempting to create and return a char [][]
.
So first decide what kind of object you need to return, then be consistent in what the function creates and returns. The following illustrates for example, to create and return a 2D char array of the form char *[]
. The void *
return type accommodates this:
void * arr_2d_alloc (size_t x, size_t y)
{
char (*pArr)[x] = malloc( sizeof (char [x][y]) ); // allocate a true 2D array
if(pArr)
{
memset(pArr, 0, sizeof **pArr);
}
return pArr;
}
Prior to creating an array like the one above, for your purposes, you will want to determine how many words are in the string you are reading, and perhaps the longest word in that collection. You can then use those values to set useful values x
an y
in the example below x
and y
are just set to random values for illustration.
Calling this function is done like this:
int main (void)
{
size_t x = 3;
size_t y = 4;
char c = 'A';
char (*p2dArr)[y] = arr_2d_alloc (x, y);
if(p2dArr)
{
//use array
for(int i = 0;i<x;i )
{
for (int j=0;j<y;j )
{
p2dArr[i][j] = c ;
printf("%c", p2dArr[i][j]);
}
}
//when done, free memory
free(p2dArr);
}
return 0;
}
CodePudding user response:
In C, you cannot return an array from a function. It's a peculiarity of the language based on design decisions way back during its development. You have a few options, this is probably not a comprehensive list:
- Dynamically allocate memory, and return a pointer to that
- Statically declare an array in the function, return a pointer to it (since it's static, it will live on beyond the life of the function)
- Wrap your array in a structure, return the structure
- Create a global array that all functions can see, don't worry about returning anything.
My personal preference is option number 1, which is demonstrated below
char** split_message(const char* message, size_t* numWords)
{
// You could do a single scan through message and reallocate space
// as needed, but in order to avoid that complexity, I'm going to do
// 2 scans through message. The first will discover where all the spaces
// are, and naively assume 1) only one space separates words and 2) there
// is a word on either size of a space. The second scan will actually
// tokenize message based on the space separators
// initialize numWords
*numWords = 0;
// get the length of message once
size_t messageLen = strlen(message);
// first scan, loop until we hit the NUL terminator at the end of message
for (size_t i=0; i<=messageLen; i )
{
if (message[i] == ' ' || message[i] == '\0')
{
// increase word count when we see a space or get to the NUL
// terminator
(*numWords) ;
}
}
printf("numWords = %zu\n", *numWords);
// Now we know how many words we have, allocate space for them
char** retWords = malloc(*numWords * sizeof(*retWords));
if (retWords == NULL) exit(-1); // handle out of mem error how you want
// second scan
size_t wordStartIndex = 0;
size_t wordIndex = 0;
for (size_t i=0; i<=messageLen; i )
{
if (message[i] == ' ' || message[i] == '\0')
{
// save the word length to a local
size_t wordLength = i - wordStartIndex;
// found the next space
// allocate space, 1 for NUL terminator
retWords[wordIndex] = malloc(wordLength 1);
if (retWords[wordIndex] == NULL) exit(-1); // handle error
// copy the word into the buffer
memcpy(retWords[wordIndex], message wordStartIndex, wordLength);
// NUL terminate
retWords[wordIndex][wordLength] = '\0';
// update indexes
wordIndex ;
// _assumes_ next word starts after this space. That could be a
// bad assumption depending on message
wordStartIndex = i 1;
}
}
return retWords;
}
Note how I've done this is not bulletproof. Leading, trailing, and multi-spaces between words will throw things off and perhaps cause problems, I haven't extensively tested it. It also does not weed out any punctuation that may exist.
I also assume you're doing this as an exercise. If not, use strtok
instead.
CodePudding user response:
Array names in C are simply pointers to the first element in the array. The most elegant way to return an array from a function is to return the array name, which enables the calling function to dereference the array elements itself. Of course, this means the calling function needs to know the size of the array, to avoid a seg fault.