Efficient way to re-assign char pointers to char arrays - arrays

I am dealing with char arrays and pointers to the arrays.
char firstAr[10] = "First";
char secondAr[10] = "Second";
char thirdAr[10] = "Third";
char* arPtrOne = firstAr;
char* arPtrTwo = secondAr;
char* arPtrThree = thirdAr;
I also have a second set of char arrays
char fourthAr[10] = "Fourth";
char fifthAr[10] = "Fifth";
char sixthAr[10] = "Sixth";
The above char arrays and char pointers can’t be altered (I have to work with them). I need to change the char arrays that my pointers point to, so that they now point to the second set of char arrays. I know I can do this by doing the following,
arPtrOne = fourthAr;
arPtrTwo = fifthAr;
arPtrThree = sixthAr;
This is fine for my example above but if I had 100 array I would need 100 statements to point them all to new char arrays. I am hoping someone could help me find a more efficient way to do this for my example above.
To stop any duplicate effort and also help others who have the same questions discover all the relevant information, This was also posted here https://forum.arduino.cc/index.php?topic=529860.0

How about using char**?
char* l_arry[100];
You can:
l_arry[0] = //your first string;
l_arry[1] = //your second string;
l_arry[2] = //your third string;

As I could not figure out how to point the existing pointers at the new char inside a loop I decided to fill the original arrays with the new char arrays contents. To do this I created all of the new char arrays inside an array char pointers so that I could reference them in a for loop. I then created a new array of char * and pointed them to the original arrays. I then used a strcpy inside a for loop to copy the contents of the new array to the original. This means that the original pointers remain unaltered and still point to the original arrays but now the arrays have updated contents. This has the same effect as pointing the pointers at new c arrays without having to actually do so.
char firstAr[10] = "First";
char secondAr[10] = "Second";
char thirdAr[10] = "Third";
char* arPtrOne = firstAr;
char* arPtrTwo = secondAr;
char* arPtrThree = thirdAr;
char *newStrings[3][10]=
{
"Fourth",
"Fifth",
"Sixth"
};
char *newPtrs[3]=
{
firstAr,
secondAr,
thirdAr
};
for(int i = 0; i<3;i++)
{
strcpy (newPtrs[i], newStrings[i]);
}

Related

Store char variables in other char variables in C

I am trying to do the following, create a multy-charr array with other char variables.
char data_info_1[] = "Wellcome.";
char data_info_2[] = "Please";
char data_info_3[] = "If";
int size_line= sizeof(data_info_1)/sizeof(data_info_1[0]);
char data_info[3][size_line]={{data_info_1},{data_info_2},{data_info_3}};
One solution would be the following one, but I am not interested in just putting the string right in the data_info variable
char data_info[3][size_line]={{"Wellcome"},{"Please"},{"If"}};
Could you please explain me why the first thing that I have writen is not valid. And if there is a solution to my problem.
Thanks.
To answer your question, neither of your solutions is correct, you can't initialize a 2D array of chars like that.
The second option would be valid if it wasn't a variable sized array, i.e.
char data_info[3][10]={"Wellcome", "Please" ,"If"};
^
Valid -> fixed size
Assignments like those would be possibe if you had an array of pointers:
char *data_info[] = {data_info_1, data_info_2, data_info_3}; //1
Or
const char *data_info[] = {"Wellcome", "Please", "If"}; //2
But these may not be what you need.
Option 1 will contain pointers to the original strings, any changes made to them through those pointers will be reflected in the original strings.
Option 2, the pointers are being initialized with string literals and those can't be changed, that's why I added the const qualifier as a metter of safety.
If neither of these constrains work for you, you'll need to copy the strings with something like strcpy, strncpy or better yet memcpy:
#include <string.h>
//...
memcpy(data_info[0], data_info_1, sizeof data_info_1);
memcpy(data_info[1], data_info_2, sizeof data_info_2);
memcpy(data_info[2], data_info_3, sizeof data_info_3);
Arrays may not be initialized by arrays. You may initialize a character array with string literals as you did in this declaration
char data_info[3][size_line]={{"Wellcome"},{"Please"},{"If"}};
Relative to your case you could declare an array of pointers to char like for example
char * data_info[] = { data_info_1, data_info2, data_info3 };
Some remarks:
you do not need to divide by sizeof char becuse it is by definition 1
You can only use constant expressions when defining or initializing global variables char data_info[3][sizeof(data_info_1)];
To "store" one char array in other you need to copy it. Initialization will not work as you cannot assign the arrays.
#include <string.h>
char data_info_1[] = "Wellcome.";
char data_info_2[] = "Please";
char data_info_3[] = "If";
char data_info[3][sizeof(data_info_1)];
void foo(void)
{
strcpy(data_info[0], data_info_1);
strcpy(data_info[1], data_info_2);
strcpy(data_info[2], data_info_3);
}
only structs or unions can be assigned. So you can wrap array into the struct and the assignment or initializations will copy the whole array.
struct stringWR
{
char str[50];
};
struct stringWR data_info_1 = {"Wellcome."};
struct stringWR data_info_2 = {"Please"};
struct stringWR data_info_3 = {"If"};
struct stringWR data_info[3];
void foo(void)
{
data_info[0] = data_info_1;
data_info[1] = data_info_1;
data_info[2] = data_info_1;
}
void bar(void)
{
struct stringWR data_info[3] = {data_info_1, data_info_2, data_info_2};
}

Dynamic two-dimensional array of pointers to strings in C

I would like to create a dynamic two-dimensional array of pointers to strings, like in the diagram below:
The program below is an extracted part of a program, and allocating dynamically stack A seems to work fine, but I'm having trouble creating a dynamic two-dimensional array of pointers to the cells of A.
// Global
char **stack_A; // dynamic array of strings
char ***stack_B; // dynamic array of pointers to strings
int main(){
stack_A = malloc(sizeof(char *));
stack_B = malloc(sizeof(char **));
function();
return 0;
}
void function(){
// example for first entry
char *text = "some text";
stack_A = realloc(stack_A, sizeof(char *)*strlen(text));
stack_A[0] = strdup(text);
stack_B[0] = realloc(stack_B[0], sizeof(char **));
stack_B[0][0] = *stack_A[0];
printf("%s", **stack_B[0][0]); // I want to output "some text"
}
Update: both the comment and answer was helpful in resolving the issue.
The problem is that you are not copying the pointer to the string, but the first charachter of the string:
stack_B[0][0] = *stack_A[0]; -> *stack_A means the first array in the group of arrays.
it means the same as stack_A[0].
*stack_A[0] means the first char in stack_A[0]: 's'
You need to copy the pointer, not the first letter:
stack_B[0][0] = *stack_A[0] becomes stack_B[0][0] = stack_A[0].

How to iterate through a char ** pointer?

I have the following code
struct my_struct {
const char **enjoy;
};
const char * enjy[] = {
"Cricket", "movie", "",
"Ball", "eat", "",
};
static const struct my_struct my_struct_table[1] = {
[0] = {
.enjoy = enjy
}
};
Now I want to use that final structure and want to iterate using that.
How can I iterate using my_struct_table[0].enjoy
I want to print all the strings in the enjy variable.
Let T be any type. When working on an array of T of varying size, represented as T*, you need to specify how the end of such array is represented.
In a simpler case: for a string of characters, i.e. T = char, the end of array char* is typically represented by a null character \0. Thus, you can iterate it as:
char* ptr = myString;
for (char c = *ptr; c; c=*++ptr) {
...
}
You iterate over all characters, until you reach the one that is \0, making the expression c evaluate to false/0 and break the loop.
An alternative representation for a string is to represent the length of the string as a separate number. This is done, for example, in Pascal strings.
int size = myStringSize;
for (int idx=0; idx<size; ++idx) {
char c = myString[idx];
}
Either of the approaches can also be used when you have an array of strings (i.e. T = char*). Your options are:
You store a special non-string value in your enjoy array set to NULL at the end of the array
Or you store the total size of the enjoy array in a separate value.
You can also use both options -- this is the case, for example, with arguments given to int main(int argc, char** argv). The argc stores the number of string values in the argv, and argv[argc] is guaranteed to be NULL.
If you use the first option you would then iterate it as:
char** ptr = enjoy;
for (char* c = *ptr; c; c=*++ptr) {
...
}
and if you use the second option:
int size = enjoySize;
for (int idx=0; idx<size; ++idx) {
char* str = enjoy[idx];
}
Notice the similarity of these snippets iterating over char**, to those used for iterating over a simple char*.
Note that a value NULL stored in the enjoy array is different than storing a pointer to an empty string. The latter should not be used as a marker for the end of the array, because it can lead to hard-to-track bugs when a legitimate empty-string value is added to your enjoy array.

Trouble with strings in C

I'm newbie in C world and I have two probably stupid questions.
I'm reading about structures in C and here is where I stuck. Let say we have structure like this
typedef structs {
char model[50];
int yearOfManufacture;
int price;
} Car;
Car Ford;
Ford.yearOfManufacture = 1997;
Ford.price = 3000;
//The line below gives me an error "Array type char[50] is not assignable
Ford.model = "Focus"
How to pass text into Ford.model in that case ?
My second question is also about strings.
This code works fine
char model[50] = "Focus";
printf("Model is %s", model);
But this one doesn't
char model[50];
model = "Focus";
Can anyone explain why it doesn't work ?
That's not how you copy strings in C. Try
strcpy(Ford.model, "Focus");
Alternatively (but with very different semantics):
typedef structs {
char const *model;
int yearOfManufacture;
int price;
} Car;
model = "Focus";
These C FAQs explain more about the issue:
Assign to array
How can an array be an lvalue, if you can't assign to it?
There are two ways to "put values in objects":
with initialization, when the object is created
with assignment, after the object is created
Though the syntax is similar, they represent different concepts.
You can initialize an array, but you cannot assign to it.
Also there's a special construct to initialize char arrays based on string literals
char arr[] = "foobar";
char arr[] = {'f', 'o', 'o', 'b', 'a', 'r', '\0'};
int arr[] = {1, 2, 3, 4};
// ...
but, assignement must be done element by element
char arr[4];
arr[0] = arr[1] = arr[2] = 'X';
arr[3] = '\0';
int arr[4];
arr[0] = arr[1] = arr[2] = 42;
arr[3] = -1;
A "special" way to assign elements of a char arrays one-by-one with a single statement is to use the library function strcpy() with prototype in <string.h>
#include <string.h>
int main(void) {
char arr[10];
strcpy(arr, "foo"); // same as arr[0]='f'; arr[1]=arr[2]='o'; arr[3]='\0';
return 0;
}
This (Ford.model = "Focus") is not possible. You have to copy the string into the array in the struct, best with strcpy:
strcpy(Ford.model, "Focus");
If your stdlib supports it, you should also consider an overflow safe version, e.g strncpy:
strncpy(Ford.model, "Focus", sizeof Ford.model);
At least I think its an extension function and not in the standard... I'm not sure.
You can't assign to a character array with =, you can only initialize it.
When you write
char model[50] = "Focus";
that is a initialization.
When you write
model = ...
that is an assignment. And, as I said, assignment to character arrays is not allowed.
You need to copy to the character array using strcpy(), e.g. strcpy(model, "Focus").
You can assign a string during definition, but anywhere else you have to use a different method, like the strcpy() function:
char model[50];
strcpy(model, "Focus");

Assigning strings to arrays of characters

I am a little surprised by the following.
Example 1:
char s[100] = "abcd"; // declare and initialize - WORKS
Example 2:
char s[100]; // declare
s = "hello"; // initalize - DOESN'T WORK ('lvalue required' error)
I'm wondering why the second approach doesn't work. It seems natural that it should (it works with other data types)? Could someone explain me the logic behind this?
When initializing an array, C allows you to fill it with values. So
char s[100] = "abcd";
is basically the same as
int s[3] = { 1, 2, 3 };
but it doesn't allow you to do the assignment since s is an array and not a free pointer. The meaning of
s = "abcd"
is to assign the pointer value of abcd to s but you can't change s since then nothing will be pointing to the array.
This can and does work if s is a char* - a pointer that can point to anything.
If you want to copy the string simple use strcpy.
There is no such thing as a "string" in C. In C, strings are one-dimensional array of char, terminated by a null character \0. Since you can't assign arrays in C, you can't assign strings either. The literal "hello" is syntactic sugar for const char x[] = {'h','e','l','l','o','\0'};
The correct way would be:
char s[100];
strncpy(s, "hello", 100);
or better yet:
#define STRMAX 100
char s[STRMAX];
size_t len;
len = strncpy(s, "hello", STRMAX);
Initialization and assignment are two distinct operations that happen to use the same operator ("=") here.
1 char s[100];
2 s = "hello";
In the example you provided, s is actually initialized at line 1, not line 2. Even though you didn't assign it a value explicitly at this point, the compiler did.
At line 2, you're performing an assignment operation, and you cannot assign one array of characters to another array of characters like this. You'll have to use strcpy() or some kind of loop to assign each element of the array.
To expand on Sparr's answer
Initialization and assignment are two distinct operations that happen to use the same operator ("=") here.
Think of it like this:
Imagine that there are 2 functions, called InitializeObject, and AssignObject. When the compiler sees thing = value, it looks at the context and calls one InitializeObject if you're making a new thing. If you're not, it instead calls AssignObject.
Normally this is fine as InitializeObject and AssignObject usually behave the same way. Except when dealing with char arrays (and a few other edge cases) in which case they behave differently. Why do this? Well that's a whole other post involving the stack vs the heap and so on and so forth.
PS: As an aside, thinking of it in this way will also help you understand copy constructors and other such things if you ever venture into C++
Note that you can still do:
s[0] = 'h';
s[1] = 'e';
s[2] = 'l';
s[3] = 'l';
s[4] = 'o';
s[5] = '\0';
I know that this has already been answered, but I wanted to share an answer that I gave to someone who asked a very similar question on a C/C++ Facebook group.
Arrays don't have assignment operator functions*. This means that you cannot simply assign a char array to a string literal. Why? Because the array itself doesn't have any assignment operator. (*It's a const pointer which can't be changed.)
arrays are simply an area of contiguous allocated memory and the name
of the array is actually a pointer to the first element of the array.
(Quote from https://www.quora.com/Can-we-copy-an-array-using-an-assignment-operator)
To copy a string literal (such as "Hello world" or "abcd") to your char array, you must manually copy all char elements of the string literal onto the array.
char s[100]; This will initialize an empty array of length 100.
Now to copy your string literal onto this array, use strcpy
strcpy(s, "abcd"); This will copy the contents from the string literal "abcd" and copy it to the s[100] array.
Here's a great example of what it's doing:
int i = 0; //start at 0
do {
s[i] = ("Hello World")[i]; //assign s[i] to the string literal index i
} while(s[i++]); //continue the loop until the last char is null
You should obviously use strcpy instead of this custom string literal copier, but it's a good example that explains how strcpy fundamentally works.
Hope this helps!
I am annoyed by this... It really would be logical if:
char string[10] = "hello";
should give the same result as:
char string[10] = {0};
string = "hello"; // doesn't work!
But I guess it just doesn't work like that. Anyways, here was my workaround:
char string[10] = {0};
sprintf(string,"hello");
its almost as good, because it is short.
Strangely enough, another thing which has worked for me (though a little off-topic perhaps) is when you declare arrays of structs, you can initialize them with the good-ole double quotes like this:
struct myStruct {
char name[NAX_NAME_LEN];
};
struct myStruct name[DATA_ARRAY_SIZE];
name[1] = (struct myStruct ) { "Hello" };
Incidentally, this method of initialization is known as a "compound literal"
Id love to see if anyone could explain why this works to use double quotes and not the string = "hello"; way...
This method is great if you have a lot of strings by the way, because it allows you to write code like:
#define DATA_ARRAY_SIZE 4
enum names{ BOB, GEORGE, FRANK, SARAH};
struct myStruct {
char name[NAX_NAME_LEN];
};
struct myStruct name[DATA_ARRAY_SIZE];
name[BOB ] = (struct myStruct ) { "Bob" };
name[GEORGE] = (struct myStruct ) { "George" };
name[FRANK ] = (struct myStruct ) { "Frank" };
name[SARAH ] = (struct myStruct ) { "Sarah" };
Or if you're going to go all multilingual for some app:
#define NUM_LANGUAGES 4
enum languages{ ENGLISH , FRENCH , SWEDISH , ITALIAN };
struct myStruct {
char intro[NAX_NAME_LEN];
};
struct myStruct name[DATA_ARRAY_SIZE];
intro[ENGLISH ] = (struct myStruct ) { "Hello" };
intro[FRENCH ] = (struct myStruct ) { "Bonjour" };
intro[SWEDISH ] = (struct myStruct ) { "Hej" };
intro[ITALIAN ] = (struct myStruct ) { "Ciao" };
You can use this:
yylval.sval=strdup("VHDL + Volcal trance...");
Where
yylval is char*. strdup from does the job.
What I would use is
char *s = "abcd";

Resources