KEEP IN MIND I WROTE THIS CODE IN HERE TO SIMPLIFY MY QUESTION, PLEASE IGNORE MINOR MISTAKES IF THERE ARE ANY, MY PROBLEM FOCUSES ON MANIPULATING AN ARRAY OUTSIDE OF A FUNCTION BY USING IT'S POINTER.
I create a static array like this
char *array[size1][size2];
For the purposes of my example size1 = 3 and size2 = 6.
Then I use a function to pass the pointer of the array, and allocate strings to it.
int counter = 0;
void somefunction(char *a, char *b, int size1){
while(counter<size1){
//do some stuff to a
strcpy(b+counter, a);
counter++;
printf("Adding %s to pos %i RESULT: %s\n",a,counter,b+counter);
}
}
This works nicely and the output is correct (when outputting array b in the function), but it does not actually effect the array[] outside of the function. If I use
somefunction(a,array,size1);
The output will be correct, but the actual array outside of the function (array[]) will output gibberish random memory.
I output it like this:
for(int i=0;i<size1;i++){
printf("%s\n",array[i]);
}
So what am i doing wrong here? I thought the array when passed to a function decays into a pointer to the first element (and therefore that array), but that doesn't seem to be the case. What am I doing wrong? How do I manipulate the array outside of the function by passing it's pointer?
Thanks!
From the comments:
What Im trying to do is I calculate the length of the string (size2). So all of the strings contained will be of length 3 in this case, "ABC" for example. Size 1 is simply the amount of strings of size 3 that I need to store and iterate through. So size1=6 size2=3 means I want to have 6 strings accesable by ordered array, all of which are 3 chars in length. Once I compute size1 and size2 (I do this before creating the array) they do indeed stay constant.
In that case, you want to declare array as a 2D array of char:
char array[size1][size2]; // no *
Note that to store a string of length N, you need an N+1-element array to account for the 0 terminator. So if you're storing strings like "ABC" ({'A','B','C',0}), then size2 needs to be 4, not 3.
When you pass it to somefunction, the type of the expression array "decays" to "pointer to size2-element array of char" (char (*)[size2])1. Based on your description, it sounds like you declare array as a variable-length array (i.e., size1 and size2 are not known until runtime). If that's the case, then your function definition needs to look like
/**
* size2 must be declared in the argument list before char (*b)[size2]
* b may also be declared as char b[][size2]; it means the same thing
*/
void somefunction( char *a, size_t size2, char (*b)[size2], size_t size )
{
...
strcpy( b[counter], a );
...
}
and should be called as
somefunction( a, size2, array, size1 );
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 will be the address of the first element of the array. In your case, N is size1 and T is "size2-element array of char".
I believe you just need this:
char *array[SIZE];
Some function then looks like this:
int counter = 0;
void somefunction(char *a, char **b){
while(counter < SIZE){
//do some stuff to a
*(b+counter) = calloc(sizeof(char), strlen(a)+1);
strcpy(*(b+counter), a);
counter++;
printf("Adding %s to pos %i RESULT: %s\n",a,counter,b+counter);
}
}
Related
I'm having trouble working with strings in C. Here is my function which takes an array of strings and returns a randomly selected one. randint(int n) is a function which returns a random integer from 1 to n.
int rand_word(const char ARR[]) {
int r = randint(sizeof(ARR));
return(ARR[r]);
}
Here is my main():
int main() {
const char *WORDS[3];
WORDS[0] = "a";
WORDS[1] = "b";
WORDS[2] = "c";
printf("%s", rand_word(WORDS));
return 0;
}
I expected to see either "a", "b", or "c" printed.
[Error] cannot convert 'const char**' to 'const char*' for argument '1' to 'int rand_word(const char*)'
Essentially my confusion is between data types. What have I done wrong? Thanks.
Ignoring the fact that rand_word is 100% wrong lets just deal with the error message.
YOu have a function that is declared as taking at char array (char[]) as an argument. You are passing it and array of pointers to a char array. Thats not valid.
Change rand_word to accept char *ARR[]
now rand_word is wrong
a) sizeof (ARR) will always be 4 or 8. Its the size of a pointer. you cannot inspect a pointer to an array and determine the length of the array. Pass in a second argument with the length
b) The function returns an int. It should return a pointer to a string
In a C function prototype, char ARR[] is really just syntactic sugar for char * because a function call converts an array into a pointer to the first element of the array. So sizeof(ARR) will have the same value as sizeof(char *). You need to pass the actual length as a separate parameter.
If randint(n) returns a number from 1 to n, be aware that array index operations in C start from index 0, not index 1, so you would need to subtract 1 from the return value of randint(n) to get an index in the range 0 to n-1.
Your rand_word function takes a pointer to the first element of an array of char and returns a single element of the array (a single char) converted to an int. But your caller passes the function a pointer to the first element of an array of const char * and expects it to return a const char * (judging from the use of the "%s" printf format specifier).
Putting that altogether, your rand_word function should look something like this:
const char *rand_word(int n, const char *ARR[])
{
int r = randint(n) - 1; // randint returns number in range 1 to n
return ARR[r];
}
Since your WORDS array has 3 elements, your printf call should be something like:
printf("%s", rand_word(3, WORDS));
You could also use this macro to get the length of an array (doesn't work on pointers):
#define ARRAY_LEN(ARR) (sizeof (ARR) / sizeof (ARR)[0])
Then your printf call can be something like this:
printf("%s", rand_word(ARRAY_LEN(WORDS), WORDS));
First, you're providing a *char[] (or char[][]) for the parameter to rand_word() instead of a char[].
Then you return a char (ARR[r]). You should use %c instead of %s in your printf() statement because of this.
Either that or change const char ARR[] to const char* ARR[].
I practiced today some C code, especially array with return function and pointers.
And I found some code which were really confusing and want to know why it is.
So I have first a function which print all elements out of the array.
void function(int *arr)
{
...
printf("%d, arr[i]);
}
Now in main I have a 2D array and a 1D array.
int array2D[2][2] = {{1,2}, {3,4}};
int array1D[3] = {1,2,3};
function(*array2D); // Why do I need here the derefernce pointer
function(array1D); // why I don't need here the deference pointer
And in another case:
void disp( int *num)
{
printf("%d ", *num);
}
int main()
{
int arr[] = {1, 2, 3, 4, 5, 6, 7, 8, 9, 0};
for (int i=0; i<10; i++)
{
/* Passing addresses of array elements*/
disp(&arr[i]); // why i need here & and above in the function not
}
}
This is really confusing me right now. Can someone explain me this?
The first line
function(*array2D);
is equivalent to
function(array2D[0]);
So you are passing the first array [1,2]. In C an array decays into a pointer
when it is passed to a function.
However, your function function1 should also get the number of
elements of the array.
void function(int *arr, size_t len)
{
size_t i;
for(i = 0; i < len; ++i)
printf("%d\n", arr[i]);
}
Then you can call it2
int array2D[2][2] = { { 1,2} ,{3,4}};
int array1D[3] = {1,2,3};
function(*array2D, sizeof *array2D / sizeof **array2D);
function(array1D, sizeof array1D / sizeof *array1D);
disp (&arr[i]); // why i need here & and above in the function not
Because arr[i] would give you the value stored at the position i, disp
expects a pointer, so you use the &-operator which returns the address of the
array at the position i, which is also equivalent to arr + i.
1Don't call your functions function. Technically that is valid name, but it
would be better if you give your function more explicit names so that just by
reading the name, you know what the functions does.
2Note that sizeof array / sizeof *array only works with arrays. If you have a
function and you expect an array, you will get only a pointer to the array.
In this case you also would need to pass the length of the array.
We're used to the fact that int mike[10] decays to int *, which points to the first thing in the array. So it seems like int sam[5][10] might also decay to int * pointing to the first element of the array. But int sam[5][10] is not a "two-dimensional array of int" that decays to an int pointer, it's an array of five arrays of ten integers. The first thing in sam is the first of the five arrays, so sam decays to a pointer to an array of ten integers, which type is written int (*)[10], though it rarely is written.
So your array2D decays to a different type than integer pointer, which is why your call function(array2D); creates a type mismatch. But your call function(*array2D); does work because (as noted above) *array2D is the same as array2D[0], which is an array of integers, and does decay to int *.
For your second case, arr is an array, but arr[i] is an int, since it is just one position in the array. The ampersand operator makes a pointer of what it operates, so &arr[i] is a pointer, and the call works.
Edit: Ok returning the matrix bit is now ok but still can't get entering rows of values down. It still only gives one value.
Quite new to C so apologies for the long read and terrible coding.
This is for a homework hence why it has to be so specific but the homework reads as:
Prompt for the size of the multiplier, which may be no bigger than ten in either dimension. Read
the elements by row, one row per line of input. If the
actual input matrix has different number of row or column as specified in the former step, print an error message and end the program.
So it needs to read in
1 0 0
1 0 0
1 0 0
and see if thats the size as declared earlier. It needs to do this for two separate matrices hence why I'm using a function, and then it will multiply the two matrices. What I currently have is
void matrix(int x, int y)
{
int i, j;
char c;
i = 0;
j = 0;
while (j < x)
{
while (c != '\n')
{
scanf("%d%c", &input[i][j], &c);
}
++j;
c = 0;
}
}
Where x and y are the size of the matrix and input[10][10] is a global array which I'm using to transfer the values out of the function to main.
Is there a way to do this with pointers? I know there are ways of doing it but my problem is that cause its for a homework we can only use what we "know" so I can only use scanf to read in variables.
Another problem I'm having is reading in the row elements, it only accepts the last element I input (which it takes as the first element) and leaves the rest blank.
Best way to do this is to pass the array as a parameter to the function, rather than try to return it.
C's treatment of arrays is special. 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" is converted ("decays") to an expression of type "pointer to T" and the value of the expression is the location of the first element of the array1.
For example, let's assume the following code:
int main( void )
{
int arr[10]; // start with a 1D array for now
foo( arr );
return 0;
}
In the function call foo( arr ), the expression arr has type "10-element array of int" (int [10]). Since it's not the operand of the sizeof or unary & operators, it "decays" to an expression of type "pointer to int" (int *), and the value of the expression is the address of arr[0].
Thus, the definition of foo would look like this:
void foo( int *a ) { ... }
What foo receives is a pointer value, not an array. C allows you to write that prototype as
void foo( int a[] ) { ... }
or even
void foo( int a[10] ) { ... }
But, in the context of a function parameter declaration, T a[] and T a[N] are interpreted as T *a; they declare a as a pointer to T, not an array of T.
The subscript operator [] is defined in terms of pointer arithmetic - a[i] == *(a + i). This means that the [] operator can be applied to pointer expressions as well as array expressions; thus, a[i] will work2 whether a is an array of T or a pointer to T.
So, applying that to your code:
int main( void )
{
int a, b;
int input[10][10]; // make input local to main
...
matrix( a, b, input );
...
}
void matrix( int x, int y, int (*input)[10] ) // or input[][10], or input[10][10]
{
...
scanf( "%d%c", &input[i][j], &c );
...
}
Having said that, you will want to send an extra parameter specifying the number of rows in the array:
matrix( a, b, rows, input );
void matrix( int x, int y, size_t rows, int (*input)[10] )
{
...
}
A pointer to an N-element array is a different type than a pointer to a M-element array (where N != M), so you can't pass anything but an N x 10-element array to matrix. However, there's no way for you to know the value of N unless you pass it as a separate parameter.
A note on syntax
A pointer to an array has the form T (*p)[N]. The parens are required since the postfix [] operator has a higher precedence than the unary * operator. *p[N] is parsed as *(p[N]) - IOW, index into p and dereference the result. (*p)[N] will first dereference p, then index into the result.
An expression of type T [N][M] will "decay" to type T (*)[M].
If you're curious why this is the case, check out this paper by Ritchie describing the development of C.
Assuming i doesn't fall outside the bounds of the array or sequence being pointed to.
This isn't rocket science.
void matrix(int x, int y, int input[x][y])
{
... // fill up input[i][j] here
}
This is possible since arrays, whenever passed to functions, decay into a pointer to the first element. So with this function you will change the contents of the original array.
My program is
#define ARRLEN 10
#define SIZEALCO 128
#define MAX_STRING_LENGTH 12
in main function,
char TYPEDATA_XML_FN[ARRLEN][SIZEALCO];
char TYPEDATA_MD5_FN[ARRLEN][SIZEALCO];
char identifier[ARRLEN][MAX_STRING_LENGTH];
char Temppath[SIZEALCO];
int arraynum;
// ...
arraynum = 0;
for(arraynum = 0; arraynum <ARRLEN; arraynum++)
{
/* Create the file name with the path*/
strcpy(Temppath,"/fw/TYPEDATA/");
nameFil(Temppath,identifier[arraynum],TYPEDATA_XML_FN[arraynum],TYPEDATA_MD5_FN[arraynum]);
}
subfunction is :
void nameFil(char *SourPath,char *InPinName,char *FilePathNameXml,char *FilePathNameMd5)
{
sprintf(FilePathNameXml, "%s\\%s_TYPEDATA.XML",SourPath,InPinName);
sprintf(FilePathNameMd5, "%s\\%s_TYPEDATA.MD5",SourPath,InPinName);
}
I checked with your example. I used (trial)
char** a = calloc(ARRLEN, sizeof(char *));
for(i = 0; i < ARRLEN ; ++i)
a[i] = ucmalloc(MAX_STRING_LENGTH);
pase(a);
subfunction :
void pase(char b[ARRLEN][MAX_STRING_LENGTH])
{
// ...
}
Now I got the warning message as "warning: passing arg 1 of `pase' from incompatible pointer type".
Actually, I would like to pass the full string array identifier,TYPEDATA_XML_FN,TYPEDATA_MD5_FN. Now I am passing single string to the subfunction. Kindly guide me. Thank you
The prototype void pase(char b[ARRLEN][MAX_STRING_LENGTH]) is rather mis-leading,
void pase(char b[][MAX_STRING_LENGTH])
would be better, since otherwise there is the implication of bounds checking (the first array dimension is ignored).
The reason why you get "incompatible pointer type" is because a is an array of pointers. If a was incremented (as a pointer itself) then the address would increase by the size of a pointer. However, b is an array of arrays of size MAX_STRING_LENGTH, so if b was incremented then the value would increase by MAX_STRING_LENGTH.
The way you have allocated the array a will (probably) not give you contiguous memory, which is what is required here. You could achieve what you want using an array of pointers, but you really must decide what you want to do. If you want to use [][] notation then you need to
calloc(MAX_STRING_LENGTH,ARRLEN);
You are getting confused because although an one dimensional array char[] behaves like a pointer char *, in two dimensions a char[][N] is not convertible to a char **, being actually more like a (*char)[N] (pointer to arrays of length n of char).
So if you want to make a function that receives a two dimensional array, you have two choices:
Use pointers to pointers:
void f(char ** array, int nrows, int ncols);
To create a char**, do like you are already doing now: create an array for pointers and call malloc for each one of them.
Use two dimensional arrays:
void f(char array[][NCOLS], int nrows);
//note: NCOLS is a compile time constant now
//NROWS is the first dimension and can be omited from array[NROWS][NCOLS]
The tricky bit is malloc-ing a two dimensional array:
char (*my_array)[NCOLS];
//my_identifiers is a pointer to arrays of length NCOLS
// it can be passed to any function expecting a car[][NCOLS]
my_array = malloc(number_of_rows*(sizeof *my_array));
You can also make it easier to understand all of this with a good choice of typedefs:
typedef char MY_STRING[MAX_STR_LENGTH];
//define my strings as arrays of MAX_STRING_LENGTH
void f(MY_STRING array[]);
...
MY_STRING *arr = malloc(nstrings*sizeof(MY_STRING));
f(arr);
I would like to know if there is any way to return an char array.
I tried something like this "char[] fun()" but I am getting error.
I don't want a pointer solution.
Thanks!
You can return an array by wrapping it in a struct:
struct S {
char a[100];
};
struct S f() {
struct S s;
strcpy( s.a, "foobar" );
return s;
}
Arrays cannot be passed or returned by value in C.
You will need to either accept a pointer and a size for a buffer to store your results, or you will have to return a different type, such as a pointer. The former is often preferred, but doesn't always fit.
C functions cannot return array types. Function return types can be anything other than "array of T" or "function returning T". Note also that you cannot assign array types; i.e., code like the following won't work:
int a[10];
a = foo();
Arrays in C are treated differently than other types; in most contexts, the type of an array expression is implicitly converted ("decays") from "N-element array of T" to "pointer to T", and its value is set to point to the first element in the array. The exceptions to this rule are when the array expression is an operand of either the sizeof or address-of (&) operators, or when the expression is a string literal being used to initialize another array in a declaration.
Given the declaration
T a[N];
for any type T, then the following are true:
Expression Type Decays to Notes
---------- ---- --------- -----
a T [N] T * Value is address of first element
&a T (*)[N] n/a Value is address of array (which
is the same as the address of the
first element, but the types are
different)
sizeof a size_t n/a Number of bytes (chars) in array =
N * sizeof(T)
sizeof a[i] size_t n/a Number of bytes in single element =
sizeof(T)
a[i] T n/a Value of i'th element
&a[i] T * n/a Address of i'th element
Because of the implicit conversion rule, when you pass an array argument to a function, what the function receives is a pointer value, not an array value:
int a[10];
...
foo(a);
...
void foo(int *a)
{
// do something with a
}
Note also that doing something like
int *foo(void)
{
int arr[N];
...
return arr;
}
doesn't work; one the function exits, the array arr technically no longer exists, and its contents may be overwritten before you get a chance to use it.
If you are not dynamically allocating buffers, your best bet is to pass the arrays you want to modify as arguments to the function, along with their size (since the function only receives a pointer value, it cannot tell how big the array is):
int a[10];
init(a, sizeof a / sizeof a[0]); // divide the total number of bytes in
... // in the array by the number of bytes
void init(int *a, size_t len) // a single element to get the number
{ // of elements
size_t i;
for (i = 0; i < len; i++)
a[i] = i;
}
arrays aren't 1st class objects in C, you have to deal with them via pointers, if the array is created in your function you will also have to ensure its on the heap and the caller cleans up the memory
A Very very basic code and very very basic explanation HOW TO Return
array back from a user defined function to main function..Hope It
helps!! Below I have given complete code to make any one understand
how exactly it works? :) :)
#include<iostream>
using namespace std;
char * function_Random()
{
int i;
char arr[2];
char j=65;//an ascII value 65=A and 66=B
cout<<"We are Inside FunctionRandom"<<endl;
for(i=0;i<2;i++)
{
arr[i]=j++;// first arr[0]=65=A and then 66=B
cout<<"\t"<<arr[i];
}
cout<<endl<<endl;
return arr;
}
int main()
{
char *arrptr;
arrptr=function_Random();
cout<<"We are Inside Main"<<endl;
for(int j=0;j<2;j++)
{
cout<<"\t"<<arrptr[j];
}
return 0;
}