How do I receive a char array in a C function? - c

I wish to split a "string" by the character ','.
The string holds a GPS NMEA encoded string, but that is of no matter.
My problem is that sometimes the parameter from the function that processes this char array is empty... Like nothing is in the array.
How should I correctly pass a "char string[]" to a function so that I may operate on a that parameter as I sent it(as a char array, not a char pointer to an array).
I also need to specify that I'm using mikroC for PIC.
Here is my code as of right now:
char* GPS_sateliti;
char CsatInView[] =
"$GPGSV,3,2,11,14,25,170,00,16,57,208,39,18,67,296,40,19,40,246,00*74";
GPS_sateliti = GrupeazaDupaVirgule(CsatInView, 2);
char* GrupeazaDupaVirgule( char deGasit[],int nrVirgule ){
int cVirgule = 1;
char* pch = strtok (deGasit,",");
while (pch != 0)
{
pch = strtok (0, ",");
cVirgule++;
if(nrVirgule == cVirgule){
break;
}
}
return pch;
}
The function that operates on the char array received as a parameter in debug mode, before entering the function the char array is fine, after entering it, it seems to be empty
It may be that I should receive a pointer to an array of chars??
Any sort of advice is welcome.
Thank you

How should I correctly pass a "char string[]" to a function so that I may operate on a that parameter as I sent it(as a char array, not a char pointer to an array).
You can't. A function parameter of an array type always decays as the corresponding pointer type.
There are two idiomatic solutions to this.
1. a sentinel:
The last value in the array is a special value that marks the end. This is done in C with strings. They always end with a \0 character, that is guaranteed not to occur inside the string. The function can search for that character to know where the data ends.
(Note: with this info I have to add I'm not sure what your problem is. If you pass an "empty string", as literally "", the \0 will be there, so you shouldn't have a problem)
2. explicitly passing the size:
instead of just
void foo(int bar[]);
you define a function
void foo(size_t barSize, int bar[]);
The caller knows the size of the array, so it can just pass it along.

With a pointer :
char* arr;
yourFunction(arr);
If you wish to initialize it before :
char* arr = malloc(51 * sizeof(char)); // Allocate a memory place of 50 because strings are null terminated in C
yourFunction(arr);
An other way to allocate memory to an array :
char* arr = calloc(50, sizeof(char)); // Allocate 50 memory place which size if the size of a char
With a string :
char arr[50];
char* ptr = arr;
yourFunction(ptr);
You have to know that it is impossible in C to know the size of an array when using pointer. The only thing you can do is to parse the size of the string as a parameter :
size_t size = 50;
char arr[size];
char* ptr = arr;
yourFunction(ptr, size);
If you wish to understand in detail how pointer works and how to iterate them, may be this post can help you. I think it is very interesting.
Globally, you iterate through an array via a pointer like this :
for ( int i = 0; i < size; i++)
printf("Current pointed value in the array : %c\n", ptr[i]); // or arr[i]
I guess you understand why giving the size of a pointed array as a parameter is important. Sometimes you can avoid using this parameter like this :
for ( int i = 0; i != '\0'; i++) // Because strings are null-terminated in C.
// Do something

Related

error: expected expression before ']' token when passing an array as an arguement in C

I am new to C. Was writing this so it takes the strings from the passed array and makes it a single sentence. But I got this error, I am not good with arrays in C. I can use some help from you guys. I did search an answer for this and couldn't find.
#include <stdint.h>
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
char smash(char arr[20][20]) {
char tmp[sizeof(arr)/sizeof(arr[0])];
for (int i=0; i < sizeof(arr)/sizeof(arr[0]); i++) {
strcat(tmp, arr[i]);
strcat(tmp, " ");
}
return tmp;
}
int main(){
char list[][6] = {"hello", "world"};
printf("%s", smash(list[]));
}
Error
error: expected expression before ']' token
printf("%s", smash(list[]));
^
There are quite a number of errors in this small piece of code.
First, to address the compiler error: list[] is not a valid expression. If you want to pass list to the function, leave the braces out:
printf("%s", smash(list));
This will then bring up another error. The function is expecting a char [20][20] as it's argument, but that's not what you're passing in. Since arrays as parameters are converted to a pointer, the argument type is actually char (*)[20] i.e. a pointer to an array of char of size 20. Note also that this conversion only occurs for the outermost array dimension, not all.
Since you're passing in a char [2][6] which gets converted to a char (*)[6] this is a type mismatch. So change the parameter to char arr[][6].
Then you're attempting to get the size of the array parameter inside of the function:
sizeof(arr)/sizeof(arr[0])
Since arrays cannot be directly passed to a function due to the conversion mentioned earlier, arr is actually a pointer and not an array, so you won't get the result you expect from this. You'll need to pass the number of array elements as a separate parameter.
Then you're calling strcat on tmp. This function will only work if the destination already has a null terminated string in it. Since tmp was not initialized or written to prior to the first call to strcat, you end up reading uninitialized bytes and potentially past the end of the array which will trigger undefined behavior.
This can be fixed by setting the first byte of the array to 0 before the loop to make it an empty string:
tmp[0] = 0;
for ...
Then there's the problem with the return type. The function is declared to return a char but you're giving a char * to the return statement, and at the point the function is called it is passed to printf where the %s format specifier is expecting a char * parameter.
So change the return type of the function from char to char *.
Finally, you're returning a pointer to a local variable in the function. This variable's lifetime ends when the function returns, so the returned pointer is invalid and using it will also trigger undefined behavior.
You'll need change tmp to a pointer and dynamically allocate memory for it using malloc. This also means you'll need to save the return value of the function in a separate variable which you can then pass to printf to print and then pass to free to free the memory.
After making all this changes, the resulting code should look like this:
char *smash(char arr[][6], int len) {
// enough for len strings plus len spaces
char *tmp = malloc(sizeof(arr[0]) * len + len + 1);
tmp[0] = 0;
for (int i=0; i < len; i++) {
strcat(tmp, arr[i]);
strcat(tmp, " ");
}
return tmp;
}
int main(){
char list[][6] = {"hello", "world"};
char *result = smash(list, sizeof(list)/sizeof(list[0]));
printf("%s", result);
free(result);
return 0;
}

Best way to initialize an array of strings to pass it to a function

I need to intialize an empty array of strings with fixed size ( 3 by 100 for example), pass it to a function to fill it with data and perform things like strcpy(), strcmp(), memset() on it. After the function is terminated I need to be able to read the data from my main().
What I tried so far:
char arrayofstrings[3][100] = {0};
char (*pointer)[3][100] = &arrayofstrings;
function(pointer);
Initalizing an (empty?) array of strings and initializing a pointer on the first element.
int function (char (*pointer)[3][100])
{
strcpy((*pointer)[i], somepointertostring);
strcmp((*pointer)[i], somepointertostring)
memset((*pointer)[i], 0, strlen((*pointer)[i]));
}
Is this a good way to do it? Is there an easier way to do it? Whats up with the brackets around the pointer?
C string functions expect a buffer to be null-terminated. Your arrayofstrings allocation happens on the stack. Depending on your compiler it might be initialized to all zeros or might contain garbage.
The simplest way in your case to make sure string functions won't overrun your buffers is to set the first character of each to 0 (null)
arrayofstrings[0][0] = 0x00;
arrayofstrings[1][0] = 0x00;
arrayofstrings[2][0] = 0x00;
This will give you 3, 100-char buffers that contain a valid empty "string". Note that you can only store 99 "characters" because the last character must be 0x00 (null-terminator).
char (*pointer)[3][100] = &arrayofstrings;
This is unnecessary.
Something to keep in mind about arrays in C is that the [] index is really only there to make things easier for the human programmer. Any array definition is simply a pointer to memory. The values inside the [][]...[] indexes and the type are used by the compiler to allocate the right amount of memory on the stack and do some simple math to come up with the right memory address for the element you want to access.
char arrayofstrings[3][100];
This will allocate sizeof(char)*3*100 bytes on the stack and give you a char* called 'arrayofstrings'. There's nothing special about the char* itself. It would be the same pointer if you had char arrayofstrings[300] or char arrayofstrings[3][10][10] or even long arrayofstrings[75] (char is 1 byte, long is 4 bytes).
Because you declared it as a multidimensional array with [a][b], when you ask for arrayofstrings[x][y], the compiler will calculate ((x*b)+y)*sizeof(type) and add it to the arrayofstrings pointer to get the address of the value you want. But because it's just a pointer, you can treat it like any other pointer and pass it around or cast it to other types of pointer or do pointer math with it.
You don't need the extra level of indirection.
An array, when passed to a function, is converted to a pointer to its first member. So if you declare the function like this:
int function(char (*pointer)[100])
Or equivalently:
int function(char pointer[][100])
Or:
int function(char pointer[3][100])
You can pass the array directly to the function:
function(arrayofstrings);
Then the body could look something like this:
strcpy(pointer[0], "some string");
strcpy(pointer[1], "some other string");
strcpy(pointer[2], "yet another string");
Best way to initialize an array of strings ...
char arrayofstrings[3][100] = {0}; is fine to initialize an array of strings.
In C, initialization is done only at object definition, like above.
Later code like strcpy(), assigns data to the array.
Best way to ... pass it to a function
When the C compiler supports variable length arrays, use function(size_t n, size_t sz, char a[n][sz]).
Add error checks.
Use size_t for array sizing and indexing.
#define somepointertostring "Hello World"
int function(size_t n, size_t sz, char arrayofstrings[n][sz]) {
if (sz <= strlen(somepointertostring)) {
return 1;
}
for (size_t i = 0; i < n; i++) {
strcpy(arrayofstrings[i], somepointertostring);
if (strcmp(arrayofstrings[i], somepointertostring)) {
return 1;
}
// Drop this it see something interesting in `foo()`
memset(arrayofstrings[i], 0, strlen(arrayofstrings[i]));
}
return 0;
}
void foo(void) {
char arrayofstrings[3][100] = {0};
size_t n = sizeof arrayofstrings / sizeof arrayofstrings[0];
size_t sz = sizeof arrayofstrings[0];
if (function(n, sz, arrayofstrings)) {
puts("Fail");
} else {
puts("Success");
puts(arrayofstrings[0]);
}
}
Initalizing an (empty?) array of strings and initializing a pointer on the first element.
The type of &arrayofstrings is char (*)[3][100] i.e. pointer to an object which is a 2D array of char type with dimension 3 x 100. So, this initialisation
char (*pointer)[3][100] = &arrayofstrings;
is not initialisation of pointer with first element of arrayofstrings array but pointer will point to whole 2D array arrayofstrings. That why, when accessing the elements using pointer you need bracket around it -
`(*pointer)[0]` -> first string
`(*pointer)[1]` -> second string and so on..
Is this a good way to do it? Is there an easier way to do it?
If you want pointer to first element of array arrayofstrings then you can do
char (*p)[100] = &arrayofstrings[0];
Or
char (*p)[100] = arrayofstrings;
both &arrayofstrings[0] and arrayofstrings are equivalent1).
Pass it to a function and access the array:
function() function signature should be -
int function (char (*pointer)[100])
// if you want the function should be aware of number of rows, add a parameter for it -
// int function (char (*pointer)[100], int rows)
this is equivalent to
int function (char pointer[][100])
and call it in from main() function like this -
function (p);
In the function() function you can access array as p[0], p[1] ...:
Sample program for demonstration:
#include <stdio.h>
#include <string.h>
#define ROW 3
#define COL 100
void function (char (*p)[COL]) {
strcpy (p[0], "string one");
strcpy (p[1], "string two");
strcpy (p[2], "string three");
}
int main(void) {
char arrayofstrings[ROW][COL] = {0};
char (*pointer)[COL] = &arrayofstrings[0];
function (pointer);
for (size_t i = 0; i < ROW; ++i) {
printf ("%s\n", arrayofstrings[i]);
}
return 0;
}
When you access an array, it is converted to a pointer to first element (there are few exceptions to this rule).

C string array function How call the function?

What Parameters should I give this function? I think it needs a string array but I don't know the exact syntax.
void write_file(char *result[], int len)
{
..
}
char result[10];
write_file(&(result[0]), 10);
or
char result[10];
write_file(result, 10);
which is the same, as array identifier is simply the address of its first element
Infact it does not need string array. In C, you can not send array to a function and also you can not return an array from a function. Solution? You can send "the" array's starting point and it's length. Then the receiver side can understand "the" array. About your question, you must send start position of the array as first argument and length of the array as the second argument.
char *result[] means an array of pointers to char. However the question is what is the meaning of the parameter len?
Normally with a function named something like write_file() the function would write a character string to an output and the len parameter would be the number of characters to write out.
To use this function as the function looks would mean something like:
char *myStrings[] = {
"string 0",
"string 1"
};
write_file (myStrings, 0); // passing zero as len as unsure what it is.
Or something like:
char *myStrings[20]; // array of pointers to chars
int iLoop;
for (iLoop = 0; iLoop < 20; iLoop++) {
myStrings[iLoop] = malloc(1000); // allocate a large buffer for each string
read_string (myStrings[iLoop], 1000); // some made up function to read a string
}
write_file (myStrings, 20);
What I suspect is that the function should actually be void write_file(char *result, int len) or it should be void write_file(char result[], int len) so that rather than accepting an array of pointers to char arrays (how strings are normally used in C) it should be accepting a pointer to a char array.
So the idea of write_file() would be to write a single string to a file rather than several strings.

Printing an array of characters

I have an array of characters declared as:
char *array[size];
When I perform a
printf("%s", array);
it gives me some garbage characters, why it is so?
http://www.cplusplus.com/reference/clibrary/cstdio/printf/
This url indicates printf takes in the format of: `int printf ( const char * format, ... );
#include <stdio.h>
#include <string.h>
#define size 20
#define buff 100
char line[buff];
int main ()
{
char *array[100];
char *sep = " \t\n";
fgets(line, buff, stdin);
int i;
array[0] = strtok(line, sep);
for (i = 1; i < size; i++) {
array[i] = strtok(NULL, sep);
if (array[i] == NULL)
break;
}
return 0;
}
You declare an array of characters like so:
char foo[size];
You seem to have it mixed up with char *, which is a pointer to a character. You could say
char *bar = foo;
which would make bar point to the contents of foo. (Or, actually, to the first character of foo.)
To then print the contents of the array, you can do one of the following:
// either print directly from foo:
printf("%s", foo);
// or print through bar:
printf("%s", bar);
Note, however, that C performs no initialization of the contents of variables, so unless you specifically set the contents to something, you'll get garbage. In addition, if that garbage doesn't happen to contain a \0; that is, a char with value 0, it will keep on outputting past the end of the array.
Your array is not initialized, and also you have an array of pointers, instead of an array of char's. It should be char* array = (char*)malloc(sizeof(char)*size);, if you want an array of char's. Now you have a pointer to the first element of the array.
Why are we making such a simple thing sound so difficult?
char array[SIZE];
... /* initialize array */
puts(array); /* prints the string/char array and a new line */
/* OR */
printf("%s", array); /* prints the string as is, without a new line */
The char in array after the end of what you want to be your string (ie. if you want your string to read "Hello" that would be the next char after the 'o') must be the terminating NUL character '\0'. If you use a C function to read input that would automatically be appended to the end of your buffer. You would only need to worry about doing it manually if you were individually writing characters to your buffer or something for some reason.
EDIT: As with pmg's comment, the '\0' goes wherever you want the string to end, so if you wanted to shorten your string you could just move it up closer to the front, or to have an empty string you just have array[0] = '\0';. Doing so can also be used to tokenise smaller strings inside a single buffer, just as strtok does. ie. "Part1\0Part2\0Part3\0". But I think this is getting away from the scope of the question.
ie. you wanted to store the first 3 chars of the alphabet as a string (don't know why anyone would do it this way but it's just an example):
char array[4];
array[0] = 'a';
array[1] = 'b';
array[2] = 'c';
array[3] = '\0';
printf("%s\n", array);
If you have something like char array[] = "Hello"; the '\0' is automatically added for you.
char *array[size];
array is not a char * with that, it's more like a char ** (pointer to an array of chars, with is similar to pointer to pointer to char).
If all you need is a C string, either:
char array[size];
and make sure you 0-terminate it properly, or
char *array;
and make sure you properly allocate and free storage for it (and 0-terminate it too).

Am I passing a copy of my char array, or a pointer?

I've been studying C, and I decided to practice using my knowledge by creating some functions to manipulate strings. I wrote a string reverser function, and a main function that asks for user input, sends it through stringreverse(), and prints the results.
Basically I just want to understand how my function works. When I call it with 'tempstr' as the first param, is that to be understood as the address of the first element in the array? Basically like saying &tempstr[0], right?
I guess answering this question would tell me: Would there be any difference if I assigned a char* pointer to my tempstr array and then sent that to stringreverse() as the first param, versus how I'm doing it now? I want to know whether I'm sending a duplicate of the array tempstr, or a memory address.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int main()
{
char* stringreverse(char* tempstr, char* returnptr);
printf("\nEnter a string:\n\t");
char tempstr[1024];
gets(tempstr);
char *revstr = stringreverse(tempstr, revstr); //Assigns revstr the address of the first character of the reversed string.
printf("\nReversed string:\n"
"\t%s\n", revstr);
main();
return 0;
}
char* stringreverse(char* tempstr, char* returnptr)
{
char revstr[1024] = {0};
int i, j = 0;
for (i = strlen(tempstr) - 1; i >= 0; i--, j++)
{
revstr[j] = tempstr[i]; //string reverse algorithm
}
returnptr = &revstr[0];
return returnptr;
}
Thanks for your time. Any other critiques would be helpful . . only a few weeks into programming :P
EDIT: Thanks to all the answers, I figured it out. Here's my solution for anyone wondering:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
void stringreverse(char* s);
int main(void)
{
printf("\nEnter a string:\n\t");
char userinput[1024] = {0}; //Need to learn how to use malloc() xD
gets(userinput);
stringreverse(userinput);
printf("\nReversed string:\n"
"\t%s\n", userinput);
main();
return 0;
}
void stringreverse(char* s)
{
int i, j = 0;
char scopy[1024]; //Update to dynamic buffer
strcpy(scopy, s);
for (i = strlen(s) - 1; i >= 0; i--, j++)
{
*(s + j) = scopy[i];
}
}
First, a detail:
int main()
{
char* stringreverse(char* tempstr, char* returnptr);
That prototype should go outside main(), like this:
char* stringreverse(char* tempstr, char* returnptr);
int main()
{
As to your main question: the variable tempstr is a char*, i.e. the address of a character. If you use C's index notation, like tempstr[i], that's essentially the same as *(tempstr + i). The same is true of revstr, except that in that case you're returning the address of a block of memory that's about to be clobbered when the array it points to goes out of scope. You've got the right idea in passing in the address of some memory into which to write the reversed string, but you're not actually copying the data into the memory pointed to by that block. Also, the line:
returnptr = &revstr[0];
Doesn't do what you think. You can't assign a new pointer to returnptr; if you really want to modify returnptr, you'll need to pass in its address, so the parameter would be specified char** returnptr. But don't do that: instead, create a block in your main() that will receive the reversed string, and pass its address in the returnptr parameter. Then, use that block rather than the temporary one you're using now in stringreverse().
Basically I just want to understand how my function works.
One problem you have is that you are using revstr without initializing it or allocating memory for it. This is undefined behavior since you are writing into memory doesn't belong to you. It may appear to work, but in fact what you have is a bug and can produce unexpected results at any time.
When I call it with 'tempstr' as the first param, is that to be understood as the address of the first element in the array? Basically like saying &tempstr[0], right?
Yes. When arrays are passed as arguments to a function, they are treated as regular pointers, pointing to the first element in the array. There is no difference if you assigned &temp[0] to a char* before passing it to stringreverser, because that's what the compiler is doing for you anyway.
The only time you will see a difference between arrays and pointers being passed to functions is in C++ when you start learning about templates and template specialization. But this question is C, so I just thought I'd throw that out there.
When I call it with 'tempstr' as the first param, is that to be understood as the
address of the first element in the array? Basically like saying &tempstr[0],
right?
char tempstr[1024];
tempstr is an array of characters. When passed tempstr to a function, it decays to a pointer pointing to first element of tempstr. So, its basically same as sending &tempstr[0].
Would there be any difference if I assigned a char* pointer to my tempstr array and then sent that to stringreverse() as the first param, versus how I'm doing it now?
No difference. You might do -
char* pointer = tempstr ; // And can pass pointer
char *revstr = stringreverse(tempstr, revstr);
First right side expression's is evaluavated and the return value is assigned to revstr. But what is revstr that is being passed. Program should allocate memory for it.
char revstr[1024] ;
char *retValue = stringreverse(tempstr, revstr) ;
// ^^^^^^ changed to be different.
Now, when passing tempstr and revstr, they decayed to pointers pointing to their respective first indexes. In that case why this would go wrong -
revstr = stringreverse(tempstr, revstr) ;
Just because arrays are not pointers. char* is different from char[]. Hope it helps !
In response to your question about whether the thing passed to the function is an array or a pointer, the relevant part of the C99 standard (6.3.2.1/3) states:
Except when it is the operand of the sizeof operator or the unary & operator, or is a string literal used to initialize an array, an expression that has type ‘‘array of type’’ is converted to an expression with type ‘‘pointer to type’’ that points to the initial element of the array object and is not an lvalue.
So yes, other than the introduction of another explicit variable, the following two lines are equivalent:
char x[] = "abc"; fn (x);
char x[] = "abc"; char *px = &(x[0]); fn (px);
As to a critique, I'd like to raise the following.
While legal, I find it incongruous to have function prototypes (such as stringreverse) anywhere other than at file level. In fact, I tend to order my functions so that they're not usually necessary, making one less place where you have to change it, should the arguments or return type need to be changed. That would entail, in this case, placing stringreverse before main.
Don't ever use gets in a real program.. It's unprotectable against buffer overflows. At a minimum, use fgets which can be protected, or use a decent input function such as the one found here.
You cannot create a local variable within stringreverse and pass back the address of it. That's undefined behaviour. Once that function returns, that variable is gone and you're most likely pointing to whatever happens to replace it on the stack the next time you call a function.
There's no need to pass in the revstr variable either. If it were a pointer with backing memory (i.e., had space allocated for it), that would be fine but then there would be no need to return it. In that case you would allocate both in the caller:
char tempstr[1024];
char revstr[1024];
stringreverse (tempstr, revstr); // Note no return value needed
// since you're manipulating revstr directly.
You should also try to avoid magic numbers like 1024. Better to have lines like:
#define BUFFSZ 1024
char tempstr[BUFFSZ];
so that you only need to change it in one place if you ever need a new value (that becomes particularly important if you have lots of 1024 numbers with different meanings - global search and replace will be your enemy in that case rather than your friend).
In order to make you function more adaptable, you may want to consider allowing it to handle any length. You can do that by passing both buffers in, or by using malloc to dynamically allocate a buffer for you, something like:
char *reversestring (char *src) {
char *dst = malloc (strlen (src) + 1);
if (dst != NULL) {
// copy characters in reverse order.
}
return dst;
}
This puts the responsibility for freeing that memory on the caller but that's a well-worn way of doing things.
You should probably use one of the two canonical forms for main:
int main (int argc, char *argv[]);
int main (void);
It's also a particularly bad idea to call main from anywhere. While that may look like a nifty way to get an infinite loop, it almost certainly will end up chewing up your stack space :-)
All in all, this is probably the function I'd initially write. It allows the user to populate their own buffer if they want, or to specify they don't have one, in which case one will be created for them:
char *revstr (char *src, char *dst) {
// Cache size in case compiler not smart enough to do so.
// Then create destination buffer if none provided.
size_t sz = strlen (src);
if (dst == NULL) dst = malloc (sz + 1);
// Assuming buffer available, copy string.
if (dst != NULL) {
// Run dst end to start, null terminator first.
dst += sz; *dst = '\0';
// Copy character by character until null terminator in src.
// We end up with dst set to original correct value.
while (*src != '\0')
*--dst = *src++;
}
// Return reversed string (possibly NULL if malloc failed).
return dst;
}
In your stringreverse() function, you are returning the address of a local variable (revstr). This is undefined behaviour and is very bad. Your program may appear to work right now, but it will suddenly fail sometime in the future for reasons that are not obvious.
You have two general choices:
Have stringreverse() allocate memory for the returned string, and leave it up to the caller to free it.
Have the caller preallocate space for the returned string, and tell stringreverse() where it is and how big it is.

Resources