In C, how can I declare and use/manipulate a an array of strings?
For example, it could be
a[1]="Apples";
a[2]="Pineapples are red"
How can I access these elements and modify them?
In your code, a must be an array of pointers to char, e.g. char *a[5], to which you then assign pointers to string literals:
a[1]="Apples";
a[2]="Pineapples are red";
You can modify an element in the sense to let it point to a different string, e.g. a[1]="another fruit";. You can access an entire string like, for example, printf("%s", a[1]), and you can access single characters like, for example, char willBeA_p = a[1][1]; But you cannot modify the contents of the strings in your example, because they are string literals (and modifying string literals yields undefined behaviour). So a[1][1]='b' is not allowed.
you can define an array of strings like:
char * array_of_strings[100];
and use malloc to allocate memory for each of them.
array_of_strings[0] = (char *) malloc(100);
array_of_strings[0] = "here is your string";
Declaration: data_type array_name[array_size];
Example: float mark[5];
You can access elements of an array by indices. Suppose you declared an array mark as above. The first element is mark[0], second element is mark[1] and so on.
It's possible to initialize an array during declaration. For example.
int mark[5] = {19, 10, 8, 17, 9};
Related
I have pointers like that. I don't know if I did this properly. I don't know how to allocate memory for them. Maybe the computer allocates memory automatically?
char *d = "Array1";
char *d1 = "Array2";
char *e = "Sum array";
Is it possible to make an array of pointers like this:
char *names[] = {"Array1","Array2","Sum array"}
And how to use this pointers when I call a function?
I usually use (the second argument is my pointer):
writeArray(wc, e, n, arr2);
So when I use an array of pointers it will be something like that?
writeArray(wc, name[2], n, arr2);
I have pointers like that. I don't know if I did this properly. I don't know how to allocate memory for them. Maybe the computer allocates memory automatically?
char *d = "Array1";
char *d1 = "Array2";
char *e = "Sum array";
The compiler will allocate an array of char with static storage duration for each string literal and initialize the variables to point to the first character of those char arrays.
Is it possible to make an array of pointers like this:
char *names[] = {"Array1","Array2","Sum array"}
Yes (although the declaration requires a semicolon), the compiler will set the length of the names array to 3 automatically to match the number of initializers since the length has not been specified explicitly.
As before, the compiler will allocate an array of char with static storage duration for each string literal. The compiler will initialize each element of the names array to point to the first character of those char arrays.
Since the contents of these string literals match those used to initialize the d, d1 and e variable, the compiler might overlap the storage for the identical string literals. This is OK because C code must not modify the storage occupied by these string literals.
If names[] has automatic storage duration (in a function), you could declare and initialize it as follows, assuming d, d1, and e are already pointing to the correct string literals:
char *names[] = {d, d1, e};
Then the elements of names[] will be pointing to the exact same string literal char array storage as d, d1 and e.
And how to use this pointers when I call a function?
I usually use (the second argument is my pointer):
writeArray(wc, e, n, arr2);
So when I use an array of pointers it will be something like that?
writeArray(wc, name[2], n, arr2);
Yes, exactly like that.
Is it possible to make an array of pointers like this
Yes, it is.
So when I use an array of pointers it will be something like that?
Correct.
char myArray[6]="Hello"; //declaring and initializing char array
printf("\n%s", myArray); //prints Hello
myArray="World"; //Compiler says"Error expression must a modifiable lvalue
Why can't I change myArray later? I did not declare it as const modifier.
When you write char myArray[6]="Hello"; you are allocating 6 chars on the stack (including a null-terminator).
Yes you can change individual elements; e.g. myArray[4] = '\0' will transform your string to "Hell" (as far as the C library string functions are concerned), but you can't redefine the array itself as that would ruin the stack.
Note that [const] char* myArray = "Hello"; is an entirely different beast: that is read-only memory and any changes to that string is undefined behaviour.
Array is a non modifiable lvalue. So you cannot modify it.
If you wish to modify the contents of the array, use strcpy.
Because the name of an array cannot be modified, just use strcpy:
strcpy(myArray, "World");
You can't assign to an array (except when initializing it in its declaration. Instead you have to copy to it. This you do using strcpy.
But be careful so you don't copy more than five characters to the array, as that's the longest string it can contain. And using strncpy in this case may be dangerous, as it may not add the terminating '\0' character if the source string is to long.
You can't assign strings to variables in C except in initializations. Use the strcpy() function to change values of string variables in C.
Well myArray is the name of the array which you cannot modify. It is illegal to assign a value to it.
Arrays in C are non-modifiable lvalues. There are no operations in C that can modify the array itself (only individual elements can be modifiable).
Well myArray is of size 6 and hence care must be taken during strcpy.
strcpy(myArray,"World") as it would result in overflow if the source's string length is more than the destination's (6 in this case).
A arrays in C are non-modifiable lvalues. There are no operations in C that can modify the array itself (only individual elements can be modifiable).
A possible and safe method would be
char *ptr = "Hello";
If you want to change
ptr = strdup("World");
NOTE:
Make sure that you free(ptr) at the end otherwise it would result in memory leak.
You cannot assign naked arrays in C. However you can assign pointers:
char const *myPtr = "Hello";
myPtr = "World";
Or you can assign to the elements of an array:
char myArray[6] = "Hello";
myArray[0] = 'W';
strcpy(myArray, "World");
In C why is it legal to do
char * str = "Hello";
but illegal to do
int * arr = {0,1,2,3};
I guess that's just how initializers work in C. However, you can do:
int *v = (int[]){1, 2, 3}; /* C99. */
As for C89:
"A string", when used outside char array initialization, is a string literal; the standard says that when you use a string literal it's as if you created a global char array initialized to that value and wrote its name instead of the literal (there's also the additional restriction that any attempt to modify a string literal results in undefined behavior). In your code you are initializing a char * with a string literal, which decays to a char pointer and everything works fine.
However, if you use a string literal to initialize a char array, several magic rules get in action, so it is no longer "as if an array ... etc" (which would not work in array initialization), but it's just a nice way to tell the compiler how the array should be initialized.
The {1, 2, 3} way to initialize arrays keeps just this semantic: it's only for initialization of array, it's not an "array literal".
In the case of:
char * str = "Hello";
"Hello" is a string literal. It's loaded into memory (but often read-only) when the program is run, and has a memory address that can be assigned to a pointer like char *str. String literals like this are an exception, though.
With:
int * arr = {0,1,2,3};
..you're effectively trying to point at an array that hasn't been put anywhere in particular in memory. arr is a pointer, not an array; it holds a memory address, but does not itself have storage for the array data. If you use int arr[] instead of int *arr, then it works, because an array like that is associated with storage for its contents. Though the array decays to a pointer to its data in many contexts, it's not the same thing.
Even with string literals, char *str = "Hello"; and char str[] = "Hello"; do different things. The first sets the pointer str to point at the string literal, and the second initializes the array str with the values from "Hello". The array has storage for its data associated with it, but the pointer just points at data that happens to be loaded into memory somewhere already.
Because there's no point in declaring and initializing a pointer to an int array, when the array name can be used as a pointer to the first element. After
int arr[] = { 0, 1, 2, 3 };
you can use arr like an int * in almost all contexts (the exception being as operand to sizeof).
... or you can abuse the string literals and store the numbers as a string literal, which for a little endian machine will look as follows:
int * arr = (int *)"\0\0\0\0\1\0\0\0\2\0\0\0\3\0\0\0";
I want to create an array of strings. The problem is that I want to be able to access the length of each string statically. I tried this:
char *a[] = {"foo", "foobar"};
The array works fine except that I want to know the length of each element statically.
I can't use sizeof(a[0]) because it returns the size of the char * pointer. What I want is the length of the size of the string (4 for a[0], 7 for a[1]).
Is there any way to do this?
In short, no, not at compile-time (at least not for an arbitrary number of strings). There are various run-time initialization-like things you can do, as others have pointed out. And there are solutions for a fixed number of strings, as others have pointed out.
The type of a[0] must be the same as that of a[1] (obviously). So sizeof() must evaluate to the same for all values of a[i].
Depending on your definition of "string", a is not an array of strings: it is an array of pointers (I define "string" as array of N characters including a null terminator).
If you want an array of lengths and strings (each capable of holding 999 characters and the null terminator), you may do something like
struct lenstring { size_t len; char data[1000]; };
struct lenstring a[] = {
{ sizeof "foo" - 1, "foo" },
{ sizeof "foobar" - 1, "foobar" },
};
Example with simplifying macro running at ideone
The only safe way to know the length of strings statically is to declare them all individually.
char foo[] = "foo";
char foobar[] = "foobar";
char *a[] = {foo, foobar};
You might be able to use a macro to eliminate some of the drudgery, depending on the strings' contents. sizeof(a[0]) will still be sizeof(char*), though.
You can't statically initialize a data structure with the result of strlen(), you could loop over your strings and store the string length in an initialization function.
You can't. sizeof doesn't return the length of the string, but the size of the array, which in your second case is much larger than the length of the string. You need to use strlen or, perhaps, a more featured string type:
struct {
size_t len;
char data[];
} string;
But it'd be a bit more complicated to make an array of them in that case.
if you use char*a[] = {"foo", ...} style of decleration, then you can use strlen(a[0]), strlen(a[1]) etc to find the length of each string.
Maybe you could start with something like this:
size1 = abs(a[0] - a[1]);
That will give you the difference between the beginning address of the first string and the beginning address of the second string. Therefore the size of the first string.
Then you could use some loop and array to get all the sizes.
It is not statically but maybe you could try it.
I'm trying to assign a compound literal to a variable, but it seems not to work, see:
int *p[] = (int *[]) {{1,2,3},{4,5,6}};
I got a error in gcc.
but if I write only this:
int p[] = (int []) {1,2,3,4,5,6};
Then it's okay.
But is not what I want.
I don't understand why the error occurrs, because if I initialize it like a array, or use it with a pointer of arrays of chars, its okay, see:
int *p[] = (int *[]) {{1,2,3},{4,5,6}}; //I got a error
int p[][3] = {{1,2,3},{4,5,6}}; //it's okay
char *p[] = (char *[]) {"one", "two"...}; // it's okay!
Note I don't understand why I got an error in the first one, and please I can't, or I don't want to write like the second form because it's needs to be a compound literals, and I don't want to say how big is the array to the compiler. I want something like the second one, but for int values.
Thanks in advance.
First, the casts are redundant in all of your examples and can be removed. Secondly, you are using the syntax for initializing a multidimensional array, and that requires the second dimension the be defined in order to allocate a sequential block of memory. Instead, try one of the two approaches below:
Multidimensional array:
int p[][3] = {{1,2,3},{4,5,6}};
Array of pointers to one dimensional arrays:
int p1[] = {1,2,3};
int p2[] = {4,5,6};
int *p[] = {p1,p2};
The latter method has the advantage of allowing for sub-arrays of varying length. Whereas, the former method ensures that the memory is laid out contiguously.
Another approach that I highly recommend that you do NOT use is to encode the integers in string literals. This is a non-portable hack. Also, the data in string literals is supposed to be constant. Do your arrays need to be mutable?
int *p[] = (int *[]) {
"\x01\x00\x00\x00\x02\x00\x00\x00\x03\x00\x00\x00",
"\x04\x00\x00\x00\x05\x00\x00\x00\x06\x00\x00\x00"
};
That example might work on a 32-bit little-endian machine, but I'm typing this from an iPad and cannot verify it at the moment. Again, please don't use that; I feel dirty for even bringing it up.
The casting method you discovered also appears to work with a pointer to a pointer. That can be indexed like a multidimensional array as well.
int **p = (int *[]) { (int[]) {1,2,3}, (int[]) {4,5,6} };
First understand that "Arrays are not pointers".
int p[] = (int []) {1,2,3,4,5,6};
In the above case p is an array of integers. Copying the elements {1,2,3,4,5,6} to p. Typecasting is not necessary here and both the rvalue and lvalue types match which is an integer array and so no error.
int *p[] = (int *[]) {{1,2,3},{4,5,6}};
"Note I don't understand why I got a error in the first one,.."
In the above case, p an array of integer pointers. But the {{1,2,3},{4,5,6}} is a two dimensional array ( i.e., [][] ) and cannot be type casted to array of pointers. You need to initialize as -
int p[][3] = { {1,2,3},{4,5,6} };
// ^^ First index of array is optional because with each column having 3 elements
// it is obvious that array has two rows which compiler can figure out.
But why did this statement compile ?
char *p[] = {"one", "two"...};
String literals are different from integer literals. In this case also, p is an array of character pointers. When actually said "one", it can either be copied to an array or point to its location considering it as read only.
char cpy[] = "one" ;
cpy[0] = 't' ; // Not a problem
char *readOnly = "one" ;
readOnly[0] = 't' ; // Error because of copy of it is not made but pointing
// to a read only location.
With string literals, either of the above case is possible. So, that is the reason the statement compiled. But -
char *p[] = {"one", "two"...}; // All the string literals are stored in
// read only locations and at each of the array index
// stores the starting index of each string literal.
I don't want to say how big is the array to the compiler.
Dynamically allocating the memory using malloc is the solution.
Hope it helps !
Since nobody's said it: If you want to have a pointer-to-2D-array, you can (probably) do something like
int (*p)[][3] = &(int[][3]) {{1,2,3},{4,5,6}};
EDIT: Or you can have a pointer to its first element via
int (*p)[3] = (int[][3]) {{1,2,3},{4,5,6}};
The reason why your example doesn't work is because {{1,2,3},{4,5,6}} is not a valid initializer for type int*[] (because {1,2,3} is not a valid initializer for int*). Note that it is not an int[2][3] — it's simply an invalid expression.
The reason why it works for strings is because "one" is a valid initializer for char[] and char[N] (for some N>3). As an expression, it's approximately equivalent to (const char[]){'o','n','e','\0'} except the compiler doesn't complain too much when it loses constness.
And yes, there's a big difference between an initializer and an expression. I'm pretty sure char s[] = (char[]){3,2,1,0}; is a compile error in C99 (and possibly C++ pre-0x). There are loads of other things too, but T foo = ...; is variable initialization, not assignment, even though they look similar. (They are especially different in C++, since the assignment operator is not called.)
And the reason for the confusion with pointers:
Type T[] is implicitly converted to type T* (a pointer to its first element) when necessary.
T arg1[] in a function argument list actually means T * arg1. You cannot pass an array to a function for Various Reasons. It is not possible. If you try, you are actually passing a pointer-to-array. (You can, however, pass a struct containing a fixed-size array to a function.)
They both can be dereferenced and subscripted with identical (I think) semantics.
EDIT: The observant might notice that my first example is roughly syntactically equivalent to int * p = &1;, which is invalid. This works in C99 because a compound literal inside a function "has automatic storage duration associated with the enclosing block" (ISO/IEC 9899:TC3).
The one that you are using is array of int pointers. You should use pointer to array :
int (*p)[] = (int *) {{1,2,3}, {4,5,6}}
Look at this answer for more details.
It seems you are confusing pointers and array. They're not the same thing! An array is the list itself, while a pointer is just an address. Then, with pointer arithmetic you can pretend pointers are array, and with the fact that the name of an array is a pointer to the first element everything sums up in a mess. ;)
int *p[] = (int *[]) {{1,2,3},{4,5,6}}; //I got a error
Here, p is an array of pointers, so you are trying to assign the elements whose addresses are 1, 2, 3 to the first array and 4, 5, 6 to the second array. The seg fault happens because you can't access those memory locations.
int p[][3] = {{1,2,3},{4,5,6}}; //it's okay
This is ok because this is an array of arrays, so this time 1, 2, 3, 4, 5 and 6 aren't addresses but the elements themselves.
char *p[] = (char *[]) {"one", "two"...}; // it's okay!
This is ok because the string literals ("one", "two", ...) aren't really strings but pointers to those strings, so you're assigning to p[1] the address of the string literal "one".
BTW, this is the same as doing char abc[]; abc = "abc";. This won't compile, because you can't assign a pointer to an array, while char *def; def = "def"; solves the problem.