I am writing a simple function in C that should build a char array from string "abc" – so it should build {'a','b','c'} – and return a pointer to that array. Here is my code for this function:
char * makeArr()
{
static char arr[3];
sprintf(arr, "%s\n", "abc");
return arr;
}
Problems occur when I call this method in main:
int main(int argc, char *argv[])
{
char *arr[3];
arr = makeArr();
return 0;
}
The compiler is complaining about casting / conflicting types. I've been playing with pointers, casting and dereferencing for quite a while now, but can't seem to get it to work. Please let me know where my logic is wrong.
Hmm ... there are several errors in this code. Let's start with the most obvious your compiler complains about:
char *arr[3];
This line declares arr to be an array of three pointers to char. What you return from your function is a single pointer to a char -> doesn't match.
Next:
static char arr[3];
sprintf(arr, "%s\n", "abc")
Here you reserve 3 chars. the sprintf() will write 5 chars. %s is replaced by the 3 characters in your string literal "abc". You add a newline character and then a 0 is added as the marker for the end of the "string". Makes 5. This btw is undefined behavior. You write past the end of your array. Code like this can be compiled, but there's no guarantee at all about what will happen at runtime.
Doing a cut here. You should read about arrays and pointers in C. If the text you're reading claims they are the same ... stop right there and find a better text. They aren't.
I'll try to explain this here briefly, so it's suitable for the Q&A style.
An array in C indeed is a contiguous space of several values. char arr[3] means a variable that holds 3 chars.
On the other hand, a char * is just a pointer pointing to a char -- this could be the first element of an array.
In C, you can't pass arrays as function parameters, and you can't return arrays from a function. Trying to do so leads to an implicit conversion: What is actually passed is a pointer to the first element of that array.
I think the last bit of information missing is what a string literal in C is: it's an array (anonymous, e.g., it doesn't have a name) containing all the characters in the double quotes plus a 0 appended. The 0 marks the end of a "string" in C.
In an expression, a string literal evaluates to a pointer to the first element.
So, something like this:
char *foo = "bar";
will lead to foo pointing to the b of the array. It's like writing
static const char no_name_0[] = { 'b', 'a', 'r', 0 };
char *foo = &(no_name_0[0]);
Among other things, you confused:
char arr[3]; // array of 3 chars.
and,
char *arr[3]; // array of 3 pointers to char.
In main(), you should only write char *arr;
Firstly, char arr[3]; is too snall to store "abc\n". It must have at least 5 elements including terminating null-character.
Then, char *arr[3]; is a 3-element array of char*.
You should assign makeArr()'s return value (it has char* type) to arr[0] or another element, or you should change the type of arr in main function to char*, which is the same type as makeArr()'s return value.
Moreover, this makeArr() doesn't make any array and returns (a pointer to) the existing array. Yoy should use malloc() to "make an array".
UPDATE:
Assigning a value of char* to the array char arr[10]; seems invalid in C.
You should use strcpy() or strncpy() (safer than strcpy()) to copy the string stored in the array between arrays.
Pass the array as an argument and modify it in the called function, would be easier. If you're statically creating the array and there's no need to allocate memory, don't, just pass around your pointers to the functions to be modified by reference
void makeArr(char arr[]){
sprintf(arr, "%s\n", "abc");
}
Simply pass the existing declared array to the makeArr function...
int main(int argc, char *argv[]) {
char arr[10];
makeArr(arr);
return 0;
}
You couldn't assign the result of makeArr to arr. I guess that's your casting error. Oversimplifying, arr points to the place on the stack where the array of 10 characters is allocated. So, I'd pass in arr to makeArr as a char*. So, you'd end up with something like this:
#include <stdio.h>
char * makeArr(char *arr)
{
sprintf(arr, "%s\n", "abc");
return arr;
}
int main(int argc, char *argv[])
{
char arr[10];
makeArr(arr);
printf("%s\n", arr);
return 0;
}
Related
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).
Closed. This question needs debugging details. It is not currently accepting answers.
Edit the question to include desired behavior, a specific problem or error, and the shortest code necessary to reproduce the problem. This will help others answer the question.
Closed 5 years ago.
Improve this question
I have this code:
char** SplitToWords(char* str);
int main()
{
char** wordarr;
char str[] = "This is a sentence";
wordarr = SplitToWords(str);
return 0;
}
After the main comes the function implementation.
I am not sure the following does what I want it to do (i.e. receive an array of strings from a function):
wordarr = SplitToWords(str);
I somehow managed to convince the compiler that it's ok, but I assume it just does something else.
If it does, how do I find out the length of the array (the number of strings in it).
Thanks
I'll try to quickly visit all aspects you might not yet fully understand:
A string in C is described as a contiguous sequence of chars, ending with a char of value 0 (as a literal: '\0'). It is not a first class object, therefore hasn't its own type. So what you use to hold a string is an array of char. Therefore, taking your question by the word, "receive an array of strings from a function" is not possible.
An array is a contiguous sequence of objects of the same type. In C, the identifier of an array doesn't have a value itself; when it's evaluated, it decays as a pointer to the array's first element instead. This is especially important when passing arrays to functions or returning them from functions -- you can't actually pass the array, you always pass a pointer
e.g. you could write:
char x[] = "foo"; // initialize a char array from a string literal
char *xp = x; // here, x evaluates as a pointer to the first element of the array
You already use pointer types for your function's argument and return value, I just think it's quite important to understand what happens entirely.
You write char** SplitToWords(char* str); and ask whether this returns an "array of strings" -- well, sort of, as you should understand after reading 1. and 2. -- What it does is returning a pointer to char *. This pointer could be a pointer to the first element of an array. So in this case, it would return a pointer to an array of char * pointers. Each of these pointers could itself be a pointer to an array of chars, therefore point to a string. But what's very important is to understand you never return an array, you always return a pointer to it. It's so important because:
You might get the idea to do something like this:
char** SplitToWords(char* str)
{
char *words[16];
// code to fill `words` with pointers to the actual words
return words; // WRONG!
}
Here, because you're not returning the array words but a pointer to it (see point 2), you return a pointer to an object that no longer exists. words is in the scope of your function and has automatic storage duration, that means it only lives as long as the execution is inside of the function. One solution would be to declare words with the static storage class specifier. This way, it lives for the entire execution time of the program. But be aware that this also means there's only a single instance ever, it's always the same object. This will be a major headache for threaded programs, for example. The other way around is to dynamically allocate words using malloc(). But then, the caller of the function must free() it later.
As for your second question, how to let the caller know the number of words -- it's in the comments already, but just for completeness, a typical approach to solve this is to append another entry that is a NULL pointer. So the caller can iterate over the pointers until it finds NULL.
Regarding your comment, of course you can create the array outside the function and pass a pointer to the function, so the function only fills it. This is a common idiom in C (e.g. think about fgets(), which takes a pointer to the char array that's filled with a string by the function).
Functions working this way will need an additional size_t parameter, so they know the size of the array they should fill through the pointer, otherwise you'd have the risk of buffer overflows (this is why gets() was finally removed from the C standard). If you decide that the caller provides the storage, your function should have this prototype:
// returns the number of words found, up to `nwords`
size_t SplitToTwords(char **words, size_t nwords, char *str);
It should be called e.g. like this:
char *words[16];
size_t nwords = SplitToWords(words, 16, "the quick brown fox"); // returns 4
Remember that the strings holding the words themselves need storage as well. You can either manipulate the bytes in str to insert a '\0' after each word, overwriting the first whitespace character (this is what strtok() does) or you can copy the words to new strings, but then you would have to malloc() each of them again and the caller has to free() them later.
Yes, you could solve it by using a function with return value char **. However, there's no way to find out how many words there are afterwards.
You can solve this by allocating one more element for the return pointer and set it to NULL. Then you can get the number of words with this code:
wordarr = SplitToWords(str);
char **ptr=wordarr;
int noWords=0;
while(!*(ptr+noWords))
noWords++;
But if you want to return multiple data in C, you either need to define a return struct or using return arguments. In this case, it could look like this for the first option:
typedef struct wordList {
char **wordarr;
int noWords;
}
wordList SplitToWords(char* str);
And the second:
char** SplitToWords(char* str, int *noWords);
or
void SplitToWords(char* str, char*** wordarr, int *noWords);
Note that there's three *. That's because we want it to be a pointer to char **
#include "stdafx.h"
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#define MAXSTRINGS 5000
int main(int argc, char *argv[]) {
char *stringTable[MAXSTRINGS];
char sentence[] = "This is a sentence";
char *token = NULL;
int i = 0;
while ((token = strtok(token == NULL ? sentence : NULL, " ")) != NULL)
{
printf("%s\n\r", token);
stringTable[i] = (char *)malloc(strlen(token) + 1); //have no "plain" C compiler - VS C++ used so cast needed :)
strcpy(stringTable[i++], token);
}
stringTable[i] = NULL; // if you need to iterate through later
printf("%d tokens found\n\r", i);
for (int y = 0; y < i; y++)
free(stringTable[y]);
}
I have used sscanf to scan in a string and add it to a structure. The only problem is that I cannot print out the string because there is no null terminator added by default. I tried to add a null in there with the strcat() function but came to the realization this cannot work. Thanks for any help.
struct a
{
int *ref;
char string[50];
}rec;
void task()
{
char *p_test;
char test[50] = "9999:STRING OF TEXT";
p_test = test;
sscanf(p_test, "%d:%[^\n]", &rec.ref, rec.string);
printf("String is:%s", &rec.string);
}
There are multiple problems with your code.
test[50] = "9999:STRING OF TEXT";
This is wrong for two reasons.
A) test is an array of char, not an array of char*. So, when you assign a string (a char*) to an element, the address is converted to a char.
B) Element 50 does not exist in your array, and writing to it invokes undefined behavior. You have an array of 50 elements with indices 0...49.
To assign an initial value to your array, all you need do is:
char test[50] = "9999:STRING OF TEXT";
And since test does not need to be modified...
const char *test = "9999:STRING OF TEXT";
If you want to zero an array, the simplest method is:
char test[50] = {0};
Of course, you don't need to if you assign the string properly to begin with, and this is not your problem.
Your string member of the a struct is a char, not a char* (a string), and using the %s format specifier when printing it invokes undefined behavior.
main is defined to return int, not void.
sscanf expects pointers to data to fill in. rec.ref is an int, you need to pass its address, i.e., &rec.ref.
You need to allocate storage for rec.string.
Here is a working example:
#include <stdio.h>
#define STRING_LEN 50
struct a
{
int ref;
char string[STRING_LEN];
} rec;
int main()
{
char test[STRING_LEN] = "9999:STRING OF TEXT";
// note that, in the real world, this may
// be a buffer overflow waiting to happen
sscanf(test, "%d:%[^\n]", &rec.ref, rec.string);
printf("String is:%s, rec is:%d", rec.string, rec.ref);
return 0;
}
You have a number of problems; a lack of null-terminator actually isn't one of them.
One problem is a syntax error; this:
char test[50]
test[50] = "9999:STRING OF TEXT";
is not valid syntax. You need:
char test[50] = "9999:STRING OF TEXT";
Another problem is that rec doesn't have a string (a char * or char[]), it just has a single character (a char). A simple approach, to get you started, is:
struct a
{
int ref;
char string[50];
} rec;
A third problem is that sscanf's arguments all have to be pointers. C is a pass-by-value language; if you just pass in an integer, that doesn't give sscanf any way to modify that integer:
sscanf(test, "%d:%[\n]", &rec.ref, rec.string); // (once rec.string is a pointer)
A fourth problem is that the format-specifier %[\n] does not mean what you seem to want it to mean. (Maybe you actually wanted %[^\n]?)
Other, smaller issues include your return-type for main (it should be int, not void).
The common thread with most of these issues is that your compiler would have eagerly helped you identify them, had you simply turned on compiler warnings!
I'm attempting to run execvp using the data from a char[][] type (aka an array of strings). Now I know that execvp() takes a pointer to a string as its first parameter and then a pointer to an array of strings as its second - in fact I have even used it successfully before as such - however I cannot seem to get the correct combination of pointers & strings to get it to work out below - whatever I try is deemed incompatible!
Any help very grateful :) - I've removed my headers to compact down the code a bit!
struct userinput {
char anyargs[30][30]; //The tokenised command
};
int main() {
struct userinput input = { { { 0 } } }; //I believe is valid to set input to 0's
struct userinput *inPtr = &input; //Pointer to input (direct access will be unavailable)
strcpy(inPtr->anyargs[0], "ls"); //Hard code anyargs to arbitary values
strcpy(inPtr->anyargs[1], "-lh");
char (*arrPointer)[30]; //Pointer to an array of char *
arrPointer = &(inPtr->anyargs[0]);
printf("arrPointer[0]: %s, arrPointer[1]: %s\n", arrPointer[0],
arrPointer[1]);
printf("At exec case; ");
execvp( arrPointer[0], arrPointer);
perror("Command not recognised"); //Prints string then error message from errno
return 0;
}
There is no such thing as char[][] in C. execvp requires an array of pointers to const char. This can be written as either char * const * or char * const [].
You however have an array of 30-characters-long arrays, not an array of pointers. The two types are not compatible, not interchangeable, and not convertible one to another in either direction.
In this line
char (*arrPointer)[30]; //Pointer to an array of char *
you attempt to declare a pointer to an array of char*, incorrectly. What you have declared instead is a pointer to char[30], which is very different from what execvp expects.
The next line
arrPointer = &(inPtr->anyargs[0]);
purports to initialize a pointer to an array of char* with a pointer to char[30], which cannot possibly be correct even if you declare a pointer to an array of char*, because the right hand side of the assignment is not a pointer to an array of char*, it's a pointer to char[30] and no sequence of casts, indices, addresses and dereferences will turn one to the other.
An array of 30 pointers to char is declared like this:
char* arguments[30];
A dynamically-sized array of pointers to char is made like this:
char** arguments = calloc (nargs, sizeof(char*));
You need to use one of those if you want to call execvp.
In either case each pointer in the array of pointers must be initialized to point to an individual NUL-terminated character array (possibly to elements of your char[30][30] array) and the last pointer (one after all the argumenrs we want to pass) must be set to NULL. (I wonder how you expected to find a NULL in a char[30][30]).
The execvp() expects as second argument a char *const argv[]. This means an array of pointers to char. This is different from a char[30][30] which is represented in memory as 30x30 contiguous chars (so no pointer).
To solve this, define your structure
struct userinput {
char *anyargs[30]; //space for 30 char* pointers
};
You could as well define anyargs as char** and initalize if dynamically with (char**)calloc(number_of_args+1,sizeof(char*))
Later, assign directly the pointers:
inPtr->anyargs[0] = "ls"; //Hard code (or use strdup() )
inPtr->anyargs[1] = "-lh";
inPtr->anyargs[2] = NULL; // end of the argument list !!!
char **arrPointer; //Pointer to an array of char *
arrPointer = inPtr->anyargs;
Edit: Caution: "The array of pointers must be terminated by a NULL pointer.".
Why is the following code illegal?
typedef struct{
char a[6];
} point;
int main()
{
point p;
p.a = "onetwo";
}
Does it have anything to do with the size of the literal? or is it just illegal to assign a string literal to a char array after it's declared?
It doesn't have anything to do with the size. You cannot assign a string literal to a char array after its been created - you can use it only at the time of definition.
When you do
char a[] = "something";
it creates an array of enough size (including the terminating null) and copies the string to the array. It is not a good practice to specify the array size when you initialize it with a string literal - you might not account for the null character.
When you do
char a[10];
a = "something";
you're trying to assign to the address of the array, which is illegal.
EDIT: as mentioned in other answers, you can do a strcpy/strncpy, but make sure that the array is initialized with the required length.
strcpy(p.a, "12345");//give space for the \0
You can never assign to arrays after they've been created; this is equally illegal:
int foo[4];
int bar[4];
foo = bar;
You need to use pointers, or assign to an index of the array; this is legal:
p.a[0] = 'o';
If you want to leave it an array in the struct, you can use a function like strcpy:
strncpy(p.a, "onetwo", 6);
(note that the char array needs to be big enough to hold the nul-terminator too, so you probably want to make it char a[7] and change the last argument to strncpy to 7)
Arrays are non modifiable lvalues. So you cannot assign to them. Left side of assignment operator must be an modifiable lvalue.
However you can initialize an array when it is defined.
For example :
char a[] = "Hello World" ;// this is legal
char a[]={'H','e','l','l','o',' ','W','o','r','l','d','\0'};//this is also legal
//but
char a[20];
a = "Hello World" ;// is illegal
However you can use strncpy(a, "Hello World",20);
As other answers have already pointed out, you can only initialise a character array with a string literal, you cannot assign a string literal to a character array. However, structs (even those that contain character arrays) are another kettle of fish.
I would not recommend doing this in an actual program, but this demonstrates that although arrays types cannot be assigned to, structs containing array types can be.
typedef struct
{
char value[100];
} string;
int main()
{
string a = {"hello"};
a = (string){"another string!"}; // overwrite value with a new string
puts(a.value);
string b = {"a NEW string"};
b = a; // override with the value of another "string" struct
puts(b.value); // prints "another string!" again
}
So, in your original example, the following code should compile fine:
typedef struct{
char a[6];
} point;
int main()
{
point p;
// note that only 5 characters + 1 for '\0' will fit in a char[6] array.
p = (point){"onetw"};
}
Note that in order to store the string "onetwo" in your array, it has to be of length [7] and not as written in the question. The extra character is for storing the '\0' terminator.
No strcpy or C99 compund literal is needed. The example in pure ANSI C:
typedef struct{
char a[6];
} point;
int main()
{
point p;
*(point*)p.a = *(point*)"onetwo";
fwrite(p.a,6,1,stdout);fflush(stdout);
return 0;
}