Normally it's a question about a buffer with a null-terminated string, but we can extrapolate it to a general case.
I have a big array of a fixed length, let's say 10:
char outputArray[10] = {'-','-','-','-','-','-','-','-','-','-'};
And I have some other (Edited: smaller) array (in my case it's a char buffer with null terminator) with a variable length. Let's say it's a buffer of 6 elements, but the actual length is indicated by another variable.
char inputArray[10] = {'h','i','/0',...some other values, i'm not interested in};
int arrLength = 2; // For my task it means a strlen(inputArray);
How to put a small array at the end of a big array, to get this:
outputArray = {'-','-','-','-','-','-','-','-','h','i'} // the null terminator isn't important, it's not about the strings, it's about arrays.
Constraints:
I can't use std, so only "native" solutions (it's for Arduino)
C++11
Code should be memory and time efficient (some elegant algorithm without too much loops and too much temporary variables or calculations please)
Thank you in advance
Edited:
Thank to #ThomasWeller for an answer. I have a small precision though. What if I need to clean all the elements before the inserted array?
For example I had some garbage
{'a','k','$','-','n','"','4','i','*','%'};
And I need to get
{'-','-','-','-','-','-','-','-','h','i'};
Do I need 2 loops? First to reset an array and the second one to set the actual result?
It can be done with a single for loop and a single variable:
for (char i=0; i<arrLength; i++)
{
outputArray[10-arrLength+i] = inputArray[i];
}
If you make arrLength a char instead of an int, this will even save you 2 bytes of memory ;-)
Use memset() to set all memory to an initial value and then memcpy() the contents at the end:
char output[10];
char input[10] = "hi\0------";
char arrLength = 2;
void setup() {
memset(output, '-', 10); // "----------"
memcpy(output+10-arrLength, input, arrLength);
Serial.begin(9600);
Serial.write(output, 10);
}
void loop() { }
Related
I am trying to make an own simple string implementation in C++. My implementation is not \0 delimited, but uses the first element in my character array (the data structure I have chosen to implement the string) as the length of the string.
In essence, I have this as my data structure: typedef char * arrayString; and I have got the following as the implementation of some primal string manipulating routines:
#include "stdafx.h"
#include <iostream>
#include "new_string.h"
// Our string implementation will store the
// length of the string in the first byte of
// the string.
int getLength(const arrayString &s1) {
return s1[0] - '0';
}
void append_str(arrayString &s, char c) {
int length = getLength(s); // get the length of our current string
length++; // account for the new character
arrayString newString = new char[length]; // create a new heap allocated string
newString[0] = length;
// fill the string with the old contents
for (int counter = 1; counter < length; counter++) {
newString[counter] = s[counter];
}
// append the new character
newString[length - 1] = c;
delete[] s; // prevent a memory leak
s = newString;
}
void display(const arrayString &s1) {
int max = getLength(s1);
for (int counter = 1; counter <= max; counter++) {
std::cout << s1[counter];
}
}
void appendTest() {
arrayString a = new char[5];
a[0] = '5'; a[1] = 'f'; a[2] = 'o'; a[3] = 't'; a[4] = 'i';
append_str(a, 's');
display(a);
}
My issue is with the implementation of my function getLength(). I have tried to debug my program inside Visual Studio, and all seems nice and well in the beginning.
The first time getLength() is called, inside the append_str() function, it returns the correct value for the string length (5). When it get's called inside the display(), my own custom string displaying function (to prevent a bug with std::cout), it reads the value (6) correctly, but returns -42? What's going on?
NOTES
Ignore my comments in the code. It's purely educational and it's just me trying to see what level of commenting improves the code and what level reduces its quality.
In get_length(), I had to do first_element - '0' because otherwise, the function would return the ascii value of the arithmetic value inside. For instance, for decimal 6, it returned 54.
This is an educational endeavour, so if you see anything else worth commenting on, or fixing, by all means, let me know.
Since you are getting the length as return s1[0] - '0'; in getLength() you should set then length as newString[0] = length + '0'; instead of newString[0] = length;
As a side why are you storing the size of the string in the array? why not have some sort of integer member that you store the size in. A couple of bytes really isn't going to hurt and now you have a string that can be more than 256 characters long.
You are accessing your array out of bounds at couple of places.
In append_str
for (int counter = 1; counter < length; counter++) {
newString[counter] = s[counter];
}
In the example you presented, the starting string is "5foti" -- without the terminating null character. The maximum valid index is 4. In the above function, length has already been set to 6 and you are accessing s[5].
This can be fixed by changing the conditional in the for statement to counter < length-1;
And in display.
int max = getLength(s1);
for (int counter = 1; counter <= max; counter++) {
std::cout << s1[counter];
}
Here again, you are accessing the array out of bounds by using counter <= max in the loop.
This can be fixed by changing the conditional in the for statement to counter < max;
Here are some improvements, that should also cover your question:
Instead of a typedef, define a class for your string. The class should have an int for the length and a char* for the string data itself.
Use operator overloads in your class "string" so you can append them with + etc.
The - '0' gives me pain. You subtract the ASCII value of 42 from the length, but you do not add it as a character. Also, the length can be 127 at maximum, because char goes from -128 to +127. See point #1.
append_str changes the pointer of your object. That's very bad practice!
Ok, thank you everyone for helping me out.
The problem appeared to be inside the appendTest() function, where I was storing in the first element of the array the character code for the value I wanted to have as a size (i.e storing '5' instead of just 5). It seems that I didn't edit previous code that I had correctly, and that's what caused me the issues.
As an aside to what many of you are asking, why am I not using classes or better design, it's because I want to implement a basic string structure having many constraints, such as no classes, etc. I basically want to use only arrays, and the most I am affording myself is to make them dynamically allocated, i.e resizable.
I am trying to store large amount of data into multiple malloc array
I have three malloc array, two 2d char array and one int array. In a test case the array name are defined as:
cres=12163;
catm=41241;
matm = (char**) malloc(catm*sizeof(char*));
for(i=0;i<catm;i++)
matm[i]=(char*) malloc(5*sizeof(char));
mres = (char**) malloc(cres*sizeof(char*));
for(i=0;i<cres;i++)
mres[i]=(char*) malloc(5*sizeof(char));
mrin = (int*) malloc(cres*sizeof(int));
I read the data from a file. The data stored in these array if printed as it is stored in the these array is in right format. But when I try to retrieve data from the character arrays, after assigning value to the int array the character; array change the column length to 14 and the value is set to 8.50000000E-01.
I am using Linux Opensuse and g++ comiler.
Any Solution or alternate method to store large amount of data.
Sorry for all the confusion the blunder was on my part i was assigning the file-handling line pointer to all the values.
So matm is an array of char* with length catm. You then assign to its elements arrays of char of length 5. Then you do the same for res instead of atm.
Finally, you allocate and store in mrin an array of cres integers.
Almost certainly you are overflowing one of these arrays. You can use valgrind to figure out which, most likely automatically, by simply running valgrind ./a.out or whatever your program is called. It will print stack traces where memory errors occur.
You may simply have strings longer than 4 characters (plus the terminating null). You don't show the code where you populate the arrays.
Since you're using a C++ compiler, you should consider using C++ containers like std::vector<char> and std::string instead of raw C arrays which are error-prone as you have discovered.
OK, so I am going to take a crack at this... in C!
What you are making are arrays of pointers to char.
So two arrays of pointer to char, each holding 41241 pointers to char
One array holding pointers to int ( although why I have no idea since just declaring an array of int of size 12163 would do the trick.
Further you are declaring each entry on the char pointer array to be 5 chars which will hold a C style string of 4 bytes plus the null terminator.
char* strArray1 [41241] ;
char* strArray2 [41241] ;
int* intArray [12163] ;
for( int x=0 ; int < 41241;x++){
strArray1[x] = malloc(5*sizeof(char)) ;
strcopy("fred",strArray1[x]);
}
for( int x=0 ; int < 41241;x++){
strArray2[x] = malloc(5*sizeof(char)) ;
strcopy("Tom",strArray2[x]);
}
for(x=0;x<12163;x++){
inArray[x*] = rand() % 50 ;
}
for( int x=0 ; int < 41241;x++){
printf(" This entry = %s \n",strArray1[x]) ;
}
for( int x=0 ; int < 41241;x++){
printf(" This entry = %s \n",strArray2[x]) ;
}
for( int x=0 ; int < 12163;x++){
printf(" This entry = %i \n",intArray[x*]) ;
}
DO NOT try and get cute with C as it will bite you in the ass every time.
I am an Arduino noob attempting to select a random name from this array:
char ns[ ][3] = {"Carlos Alberto Castronovo","Tom Erbaugh","Caterina De Giacco","Di Puglia Pugliese Filomena","Manishwar Dhillon","Mel Richards","Connie Hvidtfeldt","Amy Namehere","Tim Beck","Sanil Sethi","Christophe Lavault","Steven Grimes","Jessica Serra","Mariateresa Petrucci","Patricia Anderson","Felma Roberto Cinco","Mai Ahmed","Tobe Levy","Indah Suspriati Wibawa","Dain Turgeon Orbe","Li Wang","Ed Clark","Elodie da Silva","Jason Garcia","Allan Litswa","Pietro Zubani","Cyril Jeanpierre","Kate Denali Princess","Maria Pilar Gl","Jefferson Ricarte","Adam Reed","László Lipták","Thalia Dbl","Maria Jose Calle Salas","William Alexander","Nicole Richardson","Andrea Hescher","Ismail Sholeh","Simone Spacci","Jason Jankow"};
But I receive this error, and I am not sure about different data types and how to approach fixing this array:
error: initializer-string for array of chars is too long
Is there something basic that I am missing?
It is exactly what it is informing: your character strings are way too long to fit in your char array, so your compiler is telling you that it will not proceed any further.
You can make it work by enhancing the size of your arrays like this:
char ns[ ][30] = //... ;
The 30 here is just to represent your biggest char string; it needs to have the size of your largest predefined char string + 1 (so that the null terminating character \0 can be added). For example, if your biggest string were "apple", your array would need to be of, at least, length 6.
You can iterate through these strings by doing this, for example:
int array_items = sizeof(ns) / sizeof(*ns); // this will gives you the amount of items stored in your array
int i;
int j;
for (i = 0; i < array_items; ++i) {
size_t strSize = strlen(ns[i]); // strSize now contains, if ns[i] contained the example of apple, 5
for (j = 0; j < strSize; ++j) {
printf("%c", ns[i][j]);
}
printf("\n");
}
That [3] means each string is limited to a maximum of 3 characters. And since one has to be the null terminator, it really means two. Your strings are a lot longer than that. Choose a number that's big enough to accommodate all of them.
ETA: #JLF: are you my long lost brother? :)
I am finding it difficult to determine the length of the columns in a 2D unsigned short pointer array. I have done memory allocation correctly as far as I know. and can print them correctly.
plz see the following code segment:
int number_of_array_index_required_for_pointer_abc=3;
char A[3][16];
strcpy(A[0],"Hello");
strcpy(A[1],"World");
strcpy(A[2],"Tumanicko");
cout<<number_of_array_index_required_for_pointer_abc*sizeof(unsigned short)<<endl;
unsigned short ** pqr=(unsigned short **)malloc(number_of_array_index_required_for_pointer_abc*sizeof(unsigned short));
for(int i=0;i<number_of_array_index_required_for_pointer_abc;i++)
{
int ajira = strlen(A[i])*sizeof(unsigned short);
cout<<i<<" = "<<ajira<<endl;
pqr[i]=(unsigned short *)malloc(ajira);
cout<<"alocated pqr[i]= "<<sizeof pqr<<endl;
int j=0;
for(j=0;j<strlen(A[i]);j++)
{
pqr[i][j]=(unsigned short)A[i][j];
}
pqr[i][j]='\0';
}
for(int i=0;i<number_of_array_index_required_for_pointer_abc;i++)
{
//ln= (sizeof pqr[i])/(sizeof pqr[0]);
//cout<<"Size of pqr["<<i<<"]= "<<ln<<endl;
// I want to know the size of the columns i.e. pqr[i]'s length instead of finding '\0'
for(int k=0;(char)pqr[i][k]!='\0';k++)
cout<<(char)pqr[i][k];
cout<<endl;
}
You're almost there. You have this loop:
for(int k=0;(char)pqr[i][k]!='\0';k++) ...
Once this loop is done, k will have the length of the row. So this will give you the length of pqr[i] (not including the null terminator):
int k;
for (k=0; pqr[i][k] != 0; k++)
;
cout<<"The length is "<< k <<endl;
Edit:
You now added that you want to know the size even if the null terminator is not there. There is no way to do that. You will need to either have some kind of terminator, or store the size somewhere. If you use vector<unsigned short>, it will store the size for you. Since it also handles allocation and deallocation, it's the recommended choice.
</Edit>
Note that you have two errors in your allocation:
pqr is an array of pointers, but you're allocating a size of C*sizeof(unsigned short). that should be C*sizeof(unsigned short *) instead.
You're not allocating memory for the null terminator at the end of each string: You should be allocating (strlen(A[i])+1) * sizeof(unsigned short) for each string.
You have a bug at this line:
pqr[i][j]='\0';
At this point j is equal to strlen(A[i]) - which is outside the bounds you setup for pqr:
int ajira = strlen(A[i])*sizeof(unsigned short);
pqr[i]=(unsigned short *)malloc(ajira);
pqr[i] goes from [0] to [strlen(A[i])-1] so writing to pqr[i][strlen(A[i])] overflows the array. The compiler won't pick up on this as you allocated the memory yourself.
The solution to that bug is to do malloc(ajira+sizeof(unsigned short))
Edited after comments
My task consists of two parts. First I have to create globbal char array of 100 elements, and insert some text to it using cin. Afterwards calculate amount of chars, and create dedicated array with the length of the inputted text. I was thinking about following solution :
char[100]inputData;
int main()
{
cin >> inputData >> endl;
int length=0;
for(int i=0; i<100; i++)
{
while(inputData[i] == "\0")
{
++count;
}
}
char c = new char[count];
Am I thinking good ?
Second part of the task is to introduce in the first program dynamically created array of pointers to all inserted words. Adding a new word should print all the previous words and if there is no space for next words, size of the inputData array should be increased twice. And to be honest this is a bit too much for me. How I can create pointers to words specifically ? And how can I increase the size of global array without loosing its content ? With some temporary array ?
Regardless of the rest of your question, you appear to have some incorrect ideas about while loops. Let's look at this code.
for(int i=0; i<100; i++) {
while(inputData[i] == "\0") {
++count;
}
}
First, "\0" is not the NUL character. It is a pointer to a string containing only the terminating NUL byte. You want '\0' instead. Assuming this change, there are still problems. Let's work through what will happen:
How does a while loop work? It executes the body repeatedly, as long as the condition is true.
When does a while loop finish? When the condition is finally made false by executing the body.
What's the condition of your loop? inputData[i] == '\0', after correction.
What's the body? ++count.
Can ++count ever change the value of the condition? No, because it doesn't change i.
So, if inputData[i] is not the NUL byte, the while loop never executes.
But, if inputData[i] is the NUL byte, the while loop executes forever.
Assuming you've read a proper string into inputData, then at some point inputData[i] will be NUL, and you'll have an infinite loop.
To count the length of a standard C string, just do this
count = strlen(inputData);
If for some reason you really have to write a loop, then the following works:
int len = 0,
while (inputData[len] != '\0') {
len++;
}
After the loop, len holds the length of the string.
#include <iostream>
#include <string>
int main()
{
std::string input;
std::getline(std::cin, input);
}
Global arrays can't have the size changed dynamically unless they are a pointer to an array, in which case you can erase them and reallocate them.
Perhaps what you're after is an automatically resizing array, like a std::vector. You can see how many letters you have in the array by calling size() on the vector, and you can increase the size of the array by calling resize().
While not the most elegant solution, it might be a bit easier to use for the moment.