Pass multiple strings to function c - c

I'm learning the basics and principles of C.
I came now to pointers, strings and structs.
Now I'm working on this code to pass arrays' content to functions.
I have this code to pass content of different arrays to function.
What I succeeded to accomplish is:
How to pass one complete string because it's considered as one element of the array.
How to pass array of char and ints.
The issues I have now:
How to pass arrays of multiple strings to functions.
How to assign a pointer to the arrays to pass them also to functions.
This is my code so far:
void print_array(char *arr,int8_t cnt);
void print_array(char *arr,int8_t cnt)
{
int i;
printf("Number of elements is: %d\n",cnt);
for (i=0;i<cnt;i++)
{
printf("Elements of array: %s\n",arr);
}
}
void print_len (char *arr,int8_t cnt);
void print_len (char *arr,int8_t cnt)
{
char i,l;
for (i=0;i<cnt;i++)
{
printf ("%d\n",strlen(arr));
}
}
int main(){
char array_1 [] = {1,2,3,4,5,6,7,8};
char array_2 [] = {'1','2','3','4','5','6','7','8','9','A','B','C','D','E','F','G'};
char *array_3 [] = {"1st","2nd","3rd","4th","5th","6th"};
char *array_4 [] = {"Many of the designations used by manufacturers"};
char *array_5 [] = {"mm","End of Multiple Strings Array","simple bluetooth connection",
"datalogging purposes and accessing recorded data","THE OPERATING ENVIRONMENT"};
//int8_t *array_pointer[3]=(char*){&array_1,&array_2,&array_3};
int8_t cnt1 = sizeof(array_1)/sizeof(array_1[0]);
int8_t cnt2 = sizeof(array_2)/sizeof(array_2[0]);
int8_t cnt3 = sizeof(array_3)/sizeof(array_3[0]);
int8_t cnt4 = sizeof(array_4)/sizeof(array_4[0]);
int8_t cnt5 = sizeof(array_5)/sizeof(array_5[0]);
int8_t len1,len2,len3,len4,len5,i,t=0,x=0;
//print_len(*array_3,cnt3);
print_len(*array_5,cnt5);
//printf("Number of chars int the string#%d is: %d\n",i,t);
// this for testing strlen inside main
// I want to process this function outside main
/*for (i=0;i<cnt5;i++)
{
printf ("%d\n",strlen(array_5[i]));
}*/
//print_array(array_pointer[0],cnt1);
//print_array(array_1,cnt1);
//print_array(array_2,cnt2);
//print_array(*array_3,cnt3);
//print_array(*array_4,cnt4);
print_array(*array_5,cnt5);
return 0;
}

How to pass arrays of multiple strings to functions.
You need another function. Declare it as:
void print_array_2(char *arr[], int cnt);
Then, you can use:
print_array_2(array_3, cnt3);
How to assign a pointer to the arrays to pass them also to functions.
You can use:
char* string_array[2] = {};
string_array[0] = array_1;
string_array[2] = array_2;
print_array_2(string_array, 2);

Related

How to reverse every string in an array of strings through a function in C?

I have been trying to solve this issue for whole day, and could not do it on my own. Searching the internet didn't help me solve it either
So, this the function prototype:
void invert(char **arr, int n);
First argument is an array of strings, and the second one is number of strings in an array.
This is my code:
#include <stdio.h>
#include <string.h>
void invert(char** arr, int n)
{
int i, j, len;
for(j=0;j<n;j++)
{
len=strlen(arr[j]);
for(i=0;i<len/2;i++)
{
char tmp = arr[j][i];
arr[j][i] = arr[j][len - i - 1];
arr[j][len - i - 1] = tmp;
}
}
}
int main()
{
int n=3, i;
char **arr;
arr[0]="John";
arr[1]="Doe";
arr[2]="Programmer";
invert(arr, n);
for(i=0;i<3;i++)
{
printf("%s ",arr[i]);
}
}
The code breaks when it reaches the line:
arr[j][i] = arr[j][len - i - 1];
and I can't figure out why.
The function receives an array of strings perfectly (tested it with some printf statements for characters of specific strings), and the char tmp succesfully recieves a correct character, but the program crashed when it reaches the line mentioned earlier. Printf statements after that line don't work.
Did I miss anything? Can someone explain what am I doing wrong? Thank you!
For starters this code snippet
char **arr;
arr[0]="John";
arr[1]="Doe";
arr[2]="Programmer";
invokes undefined behavior because the pointer arr is uninitialized and has an indeterminate value.
Moreover this approach in any case is wrong because you may not change string literals.
What you need is to declare a two-dimensional array as for example
enum { N = 11 };
//...
char arr[3][N] =
{
"John", "Doe", "Programmer"
};
In this case the function declaration will look like
void invert( char arr[][N], int n );
The enumeration must be declared before the function declaration.
Instead of the two-dimensional array you could declare an array of pointers like
char s1[] = "John";
char s2[] = "Doe";
char s3[] = "Programmer";
char * arr[3] = { s1, s2, s3 };
In this case the function declaration may be as shown in your question
void invert(char** arr, int n)
So what you need to do with minimal changes is to substitute this code snippet
char **arr;
arr[0]="John";
arr[1]="Doe";
arr[2]="Programmer";
for this code snippet
char s1[] = "John";
char s2[] = "Doe";
char s3[] = "Programmer";
char * arr[3] = { s1, s2, s3 };
To begin with, what you have here:
char **arr;
is a pointer to pointer to char.
Secondly, even if you had an array of pointers to char, like so :
char *arr[3];
And then assigning each string literal :
arr[0]="John";
arr[1]="Doe";
arr[2]="Programmer";
would still invoke Undefined behavior, since you are attempting to modify a string literal which is read only.
What you need is, either a 2D array of chars :
char arr[][100] = {"John", "Doe", "Programmer"};
and also change the function signature to :
void invert(char arr[][100], int n)
or you have to dynamically allocate memory and use a function like strcpy(), strdup(), memcpy() etc :
char **arr;
arr = malloc(n * sizeof(char *)); // or sizeof(*arr)
if (arr == NULL) {
fprintf(stderr, "Malloc failed to allocate memory\n");
exit(1);
}
arr[0] = strdup("John"); // good idea to also check if strdup returned null
arr[1] = strdup("Doe");
arr[2] = strdup("Programmer");
invert(arr, n);
for(i=0;i<3;i++)
{
printf("%s ",arr[i]);
}
for (i = 0; i < 3; i++) {
free(arr[i]);
}
free(arr);

C: Initialize a constant string array dynamically

I know the problem seems weird but I need to initialize (or convert) a constant string array in C.
The problem is that the string array is initialized dynamically but an API function I'd like to use only accepts constant string arrays.
I know that this works:
const char *const arr[] = { "test" };
But again: Since I don't know how many items the array will have nor I know the content pre runtime, I can't initialize the array that way.
So of course this won't work
const char *const arr[1];
arr[1] = "test"; // won't work
My question is: Is it possible to convert somehow the dynamically string array to a read-only one? Or is there a way to initialize the array dynamically once?
EDIT 1: My exact problem
int len = 8;
const char *names1[8] = {"test0","test1","test2","test3","test4","test5","test6","test7" }; // not what I'm looking for
const char *names2[len];
const char *names3[len];
// nearly what I'm looking for
for(int j=0; j<len; j++) {
names2[j] = "test";
}
// exactly what I'm looking for
for(int j=0; j<len; j++) {
sprintf(names3[j],"%s%d","test",j); // discards 'const' qualifier
}
// ...
Cudd_DumpDot(gbm, 1, ddnodearray, names1, NULL, outfile);
Cudd_DumpDot(gbm, 1, ddnodearray, names2, NULL, outfile);
Cudd_DumpDot(gbm, 1, ddnodearray, names3, NULL, outfile); // won't work
Okay this is my progress so far.
The method with names2 is indeed working but I'd like to use sprintf (as shown with names3) since I need to append j in this case. And this would wound the const qualifier.
Technically there is nothing stopping you from casting the pointer to (char *) and then setting the elements with memset or alike.
However this invokes undefined behaviour since the compiler can put it into read-only marked memory.
Excerpt from an answer on another SO question:
The const qualifier is an instruction to the compiler to reject code
that attempts to modify that object directly; attempts to modify the
object indirectly (as you do in the second code snippet) results in
undefined behavior, meaning any result is possible.
There is no way (without invoking UB) to change a constant after its initialisation - so don't do that.
UPDATE As #chux pointed out in the comments it is indeed possible to dynamically initialize local variables.
an API function I'd like to use only accepts constant string arrays.
That's no reason to pass an array of constant pointers ... the conversion to const (in this case constant array elements) is allowed (and even implicit), so the following (nonsensical) code compiles just fine:
const char *test(const char *const *foo)
{
return foo[0];
}
int main(void)
{
const char *arr[10];
arr[0] = "Foobar";
const char *x = test(arr);
return (int) *x;
}
Initialize a constant string array dynamically
Within a function, there are various ways to initialize a const string array at run-time.
// example
const char *s[2] = { (char [3]){ rand(), 0, 0},(char [3]){ rand(), 0, 0} };
Yet it appears OP needs only something like that.
Form the various strings, each in valid memory.
// Exmaple
#define SZ (4 + 11 + 1)
char buf[len][SZ];
for(int j=0; j<len; j++) {
sprintf(buf[j],"%s%d","test",j);
}
Form an array of const char *
const char *names[len];
for(int j=0; j<len; j++) {
names[len] = buf[len];
}
Call Cudd_DumpBlifBody(). The char const *const * parameters can be called with type char const *const * or char const **
#include <stdio.h>
#include <stdlib.h>
typedef void DdManager;
typedef void DdNode;
int Cudd_DumpBlifBody(DdManager *dd, int n, DdNode **f,
char const *const *inames,
char const *const *onames, FILE *fp, int mv) {
return 0;
}
#define SZ (4 + 11 + 1)
int sw(int len) {
char buf[len][SZ];
const char *names[len];
for(int j=0; j<len; j++) {
sprintf(buf[j],"%s%d","test",j);
names[len] = buf[len];
}
char const *const *inames = names;
char const *const *onames = names;
return Cudd_DumpBlifBody (NULL, 0, NULL, inames, onames, NULL, 0);
}
Local objects like char buf[len][SZ]; could easlily get too large for local storage. Consider *alloc() if unsure or if len could be large.

How to return a multidimensional character array from a function in a header file in C

I have a main file, and a header file.
In main file, I want to return a 2D char array from a char function from header file. My char function is as following:
char character_distribution(int length, char redistribution[length][2])
{
char *buffer, distribution[256][2] = {0};
long lSize;
struct Bar result = funct();
buffer = result.x;
lSize = result.y;
length = collect_character_distribution(buffer, lSize, distribution);
reorganize_character_distribution(length, distribution, redistribution);
return redistribution;
}
And my main function is as follows:
#include <stdio.h>
#include "character_distribution.h"
void main()
{
int length;
char distribution[length][2];
distribution = character_distribution(length, distribution[length][2]);
int a;
for(a = 0; a < length; a++)
{
printf("%c\n", distribution[a][0]);
}
}
When I run my code, I get the following error:
warning: return makes integer from pointer without a cast
How can I fix the problem?
void character_distribution(int length, char redistribution[][2])
{
char *buffer, distribution[256][2] = {0};
long lSize;
struct Bar result = funct();
buffer = result.x;
lSize = result.y;
length = collect_character_distribution(buffer, lSize, distribution);
reorganize_character_distribution(length, distribution, redistribution);
}
int main()
{
int length = 2; //initialize
char distribution[length][2];
character_distribution(length, distribution);
int a;
for(a = 0; a < length; a++)
{
printf("%c\n", distribution[a][0]);
}
return 0;
}
If you really have to return the 2d array, one way (easy way) is to just put it in a struct
struct distribution_struct {
char x[256];
char y[2];
};
struct distribution_struct character_distribution(int length, char redistribution[][2]) {
struct distribution_struct dis;
//initialize the struct with values
//return the struct
}
And another way is to manually allocate memory for the 2d array in the function and return it
char** character_distribution(int length, char redistribution[][2]) {
//use malloc to create the array and a for loop to populate it
}
You cannot actually return an array from a C function. You can, however, return a pointer to such an array. The correct declaration in that case is:
char (*character_distribution(int length, char redistribution[][2]))[][2]
Sizing the initial dimension is not necessary and not, I suspect, actually conformant with standard C (at least, sizing it with length as you did in your question looks dubious to me). This is because arrays are passed by reference implicitly (and in this case, returned by reference explicitly) and it is not necessary to know the first dimension in order to calculate the address of an element having been given a pointer to the array (and the indices).
Note that you should not return a pointer to an array that is scoped locally to the function, since its storage is deallocated once the function returns (and such a pointer would then be invalid).
However, your question shows that you don't really need to return an array. Since arrays are passed by reference anyway, altering the passed-in array will causes changes that are also visible to the caller. Your code could be written as:
void character_distribution(int length, char redistribution[][2])
{
char *buffer, distribution[256][2] = {0};
long lSize;
struct Bar result = funct();
buffer = result.x;
lSize = result.y;
length = collect_character_distribution(buffer, lSize, distribution);
reorganize_character_distribution(length, distribution, redistribution);
}
And
#include <stdio.h>
#include "character_distribution.h"
void main()
{
int length = 256; // you need to initialise this...
char distribution[length][2];
// No assignment needed here!:
character_distribution(length, distribution /* [length][2] - remove this! */);
int a;
for(a = 0; a < length; a++)
{
printf("%c\n", distribution[a][0]);
}
}
(Of course this relies on the various other functions you call performing as they are supposed to).
Change the signature to this:
char** character_distribution(int length, char redistribution[length][2])
You are returning a multidimensional array, not a character.

Returning a 2D char array in C

I messed around with this enough but I really don't get it.
Here is what I want to do: Take a 2D char array as an input in a function, change the values in it and then return another 2D char array.
That's it. Quite simple idea, but ideas do not get to work easily in C.
Any idea to get me started in its simplest form is appreciated. Thanks.
C will not return an array from a function.
You can do several things that might be close enough:
You can package your array in struct and return that. C will return structs from functions just fine. The downside is this can be a lot of memory copying back and forth:
struct arr {
int arr[50][50];
}
struct arr function(struct arr a) {
struct arr result;
/* operate on a.arr[i][j]
storing into result.arr[i][j] */
return result;
}
You can return a pointer to your array. This pointer must point to memory you allocate with malloc(3) for the array. (Or another memory allocation primitive that doesn't allocate memory from the stack.)
int **function(int param[][50]) {
int arr[][50] = malloc(50 * 50 * sizeof int);
/* store into arr[i][j] */
return arr;
}
You can operate on the array pointer passed into your function and modify the input array in place.
void function(int param[][50]) {
/* operate on param[i][j] directly -- destroys input */
}
You can use a parameter as an "output variable" and use that to "return" the new array. This is best if you want the caller to allocate memory or if you want to indicate success or failure:
int output[][50];
int function(int param[][50], int &output[][50]) {
output = malloc(50 * 50 * sizeof int);
/* write into output[i][j] */
return success_or_failure;
}
Or, for the caller to allocate:
int output[50][50];
void function(int param[][50], int output[][50]) {
/* write into output[i][j] */
}
You cannot return an array from a function.
You have several options:
wrap arrays inside structs
struct wraparray {
int array[42][42];
};
struct wraparray foobar(void) {
struct wraparray ret = {0};
return ret;
}
pass the destination array, as a pointer to its first element (and its size), to the function; and change that array
int foobar(int *dst, size_t rows, size_t cols, const int *src) {
size_t len = rows * cols;
while (len--) {
*dst++ = 42 + *src++;
}
return 0; /* ok */
}
// example usage
int x[42][42];
int y[42][42];
foobar(x[0], 42, 42, y[0]);
change the original array
int foobar(int *arr, size_t rows, size_t cols) {
size_t len = rows * cols;
while (len--) *arr++ = 0;
return 0; /* ok */
}
char **foo(const char * const * bar, size_t const *bar_len, size_t len0) {
size_t i;
char** arr = malloc(sizeof(char *) * len0);
for (i = 0; i < len0; ++i) {
arr[i] = malloc(bar_len[i]);
memcpy(arr[i], bar[i], bar_len[i]);
}
/* do something with arr */
return arr;
}
Somewhere else in your code:
char **pp;
size_t *pl;
size_t ppl;
/* Assume pp, pl are valid */
char **pq = foo(pp, pl, ppl);
/* Do something with pq */
/* ... */
/* Cleanup pq */
{
size_t i;
for (i = 0; i < ppl; ++i)
free(pq[i]);
free(pq);
}
Because you're passing by-pointer instead of by-value and you want to write to the input array, you have to make a copy of it.
Here's another example. Tested and works.
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
void test(char**,unsigned int,unsigned int);
const unsigned int sz_fld = 50 + 1;
const unsigned int sz_ffld = 10;
int main(void) {
char fld[sz_ffld][sz_fld];
for (unsigned char i=0;i<sz_ffld;++i) {
strcpy(fld[i],"");
}
strcpy(fld[0],"one");
strcpy(fld[1],"two");
strcpy(fld[2],"three");
char** pfld = malloc(sz_ffld*sizeof(char*));
for (unsigned int i=0;i<sz_ffld;++i) {
*(pfld+i) = &fld[i][0];
}
test(pfld,sz_ffld,sz_fld);
printf("%s\n",fld[0]);
printf("%s\n",fld[1]);
printf("%s\n",fld[2]);
free(pfld);
return(0);
}
void test(char** fld,unsigned int m,unsigned int n) {
strcpy(*(fld+0),"eleven");
strcpy(*(fld+1),"twelve");
return;
}
Note the following:
For compiling, I am using gcc with the C99 option.
I defined the function to include the two sizes information, but I wrote very basic code and am not actually using the information at all, just the strcpy(), so this certainly is not security-safe code in any way (even though I'm showing the "m" and "n" for such facility). It merely shows a technique for making a static 2D char array, and working with it in a function through the intermediate of an array of pointers to the "strings" of the array.
When you pass a 2D array to a function as a parameter, you need to explicitly tell it the size of the arrays second dimension
void MyFunction(array2d[][20]) { ... }
The following will do what you want. it will print "One" and "Ten". Also note that it is typed to the exact array dimensions of 10 and 8.
char my_array[10][8] =
{
{"One"},
{"Two"},
{"One"},
{"One"},
{"One"},
{"One"},
{"One"},
{"One"},
{"Nine"},
{"Ten"},
};
void foo ( char (**ret)[10][8] )
{
*ret = my_array;
}
void main()
{
char (*ret)[10][8];
foo(&ret);
printf("%s\r\n", (*ret)[0] )
printf("%s\r\n", (*ret)[9] )
}
The original question was about RETURNING the array, so I'm updating this to show returning a value. You can't "return an array" directly, but you CAN make a typedef of an array and return that...
char my_array[10][8];
typedef char ReturnArray[8];
ReturnArray* foo()
{
return my_array;
}

c - grouping strings in a struct

I have a bunch of strings that look like:
'Hello1-FOO', 'Aello2-FOO', 'Bye1-BAR', 'Bye3-BAR', 'Hello22-FOO', 'Bye4-BAR', 'Welcome-BAR' ...
All of them are stored on a struct.
struct str {
char *strings;
}
...
struct str **t_str;
size_t j;
t_str = malloc(sizeof *t_str * 20);
for (j = 0; j < 20; j++)
t_str[j] = malloc(sizeof *t_str[j]);
...
t_str[0]->strings = "Hello1-FOO";
t_str[1]->strings = "Aello2-FOO";
....
What I would like to do is to display (sort) them by category, so they look similar to this:
FOO:
Hello1-FOO
Aello2-FOO
Hello22-FOO
BAR:
Bye4-BAR
Welcome-BAR
Bye1-BAR
Bye3-BAR
Basically group them by the token after the '-'
What would be a good way of doing this? Should I store them on a second struct after processing the string? Any idea will be appreciated. Thanks
Just use qsort. The following code makes some assumptions but you should be able to change it to suit your needs.
int categoryComparitor(const void * a, const void * b)
{
char *string1 = (char *)a;
char *string2 = (char *)b;
string1 = strrchr(string1, '-') + 1;
string2 = strrchr(string2, '-') + 1;
return strcmp(string1, string2);
}
{
...
char *strings[]; // Array of string pointers
int stringCount; // Holds current number of valid elements in strings.
...
qsort(strings, stringCount, sizeof(char *), categoryComparitor);
}
As David Thornley already pointed out, your struct isn't really defined well to handle this situation (well at all). Since your input is two separate logical pieces, you really want to define the struct accordingly -- containing two separate strings, one for each part of the input.
struct record {
char *category;
char *string;
};
Then you want to read each piece into one of those two strings:
record read_line(FILE *infile) {
char buffer1[128], buffer2[128];
fscanf(infile, "%[^-]-%s", buffer1, buffer2);
record ret;
ret.string = dupe_string(buffer1);
ret.category = dupe_string(buffer2);
return ret;
}
Then, to sort those records, you'll want to define a comparison function with the signature expected by qsort, that does a comparison on the category member:
int cmp(void *a, void *b) {
return strcmp(((record *)a)->category, ((record *)b)->category);
}
Then you'll sort your array of records using that comparison function.

Resources