Filling and comparing char* inside a function - c++
I wrote the function readChar() which is designed to read the characters send by my WiFi module one by one(function works has advertised) and pass them to a char buffer of increasing size. The function should stop when char *endChar (multiple characters) have been detected or the number of character returned by timedRead() has exceeded size_t length.
I have several issues:
1/. I don't understand the syntax (found inside the Arduino Stream library) :
*buffer++ = (char)c;
Can you explain how the array buffer gets filled?
And why buffer[index] = (char)c; doesn't work here?
2/. I would like to compare buffer and endChar in the loop, possibly by using strcmp(buffer,endChar) (maybe there is a better way). But that doesn't seem to work. In fact when printing the ASCII values of my char *buffer then seem to increment from the end of the buffer. E.G.:
So what is the best way to do that comparison?
The code, inserted in the loop:
_dbgSerial->println("buffer");
for (int i = 0; i < 32; i++){
_dbgSerial->print(buffer[i], DEC);
_dbgSerial->print(",");
}
_dbgSerial->println("");
prints:
buffer
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,13,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,13,10,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,13,10,13,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,13,10,13,10,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,13,10,13,10,0,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,13,10,13,10,0,0,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,13,10,13,10,0,0,0,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,13,10,13,10,0,0,0,0,
Here is the function readChar():
size_t Debugwifi::readChar(char *endChar, char *buffer, size_t length) {
if (length < 1) return 0;
size_t index = 0;
while (index < length) {
int c = timedRead();
if (c < 0 ) break;
//buffer[index] = (char)c;
*buffer++ = (char)c;
_dbgSerial->println("buffer");
for (int i = 0; i < 32; i++){
_dbgSerial->print(buffer[i], DEC);
_dbgSerial->print(",");
}
_dbgSerial->println("");
if (strcmp(buffer,endChar)==0) {
break;
_dbgSerial->println("brk");}
index++;
}
return index;
}
As Rickard has explained, *buffer++ = (char)c; is how you assign a character to the memory a pointer points at, and then increment the pointer.
However, your function has a lot of problems - you keep comparing unset memory with *endChar. I suggest:
size_t Debugwifi::readChar(const char * const endStr, // const pointer to const.
char * const buffer, const size_t length) {
if (length < 1) return 0;
const size_t endLen = strlen(endStr);
for (size_t index = 0; index < length; index++) {
const int c = timedRead();
if (c < 0 ) break;
buffer[index] = (char)c;
// Debug
_dbgSerial->println("buffer");
for (size_t i = 0; i < length; i++){ // Better to use size_t here,
// and compare against length not 32
_dbgSerial->print(buffer[i], DEC);
_dbgSerial->print(",");
}
_dbgSerial->println("");
// Finished?
if (index >= endLen) {
if (memcmp(&buffer[index-endLen], endStr, endLen)==0) {
_dbgSerial->println("brk"); // Must do this *before* "break"!
break;
}
}
}
return index;
}
I have added a lot of consts. It's hard to have too many.
The important point is that once you have read enough characters, to start comparing the last characters you have read to the end marker.
Note that this function does not remove the end marker, and if you pass a 32-byte zero-filled array and it reads 32 characters, the result will NOT be zero terminated.
Finally, I changed the argument name to endStr because I had expected endChar to be a pointer to a single character - not a NUL-terminated string.
*buffer++ = (char) c;
First writes the value of c to what buffer is currently pointing to.
Then it increments the buffer
This is also why your loop to print buffer doesn't work.
You start printing from the position after what was just filled.
This is also why your strcmp doesn't work. It doesn't actually compare what you have filled your buffer with. It compares the content beyond what have been filled.
If you want your printing code to work you should save the initial value of buffer before the loop;
const char *buffer_start = buffer;
Then use that in your printing code instead of buffer.
Related
Generate random char/digit
I`m trying to found fastest way to generate random digit/char array. char *randomGet(int num) { srand(time(NULL)); const char ab[37] = { "0123456789ABCDEFGHIGKLMNOPQRSTUVWXYZ" };//Alphabet&Digit char *targ = new char[num]; for (int i = 0; i < num; i++) { strcat(targ, ab[rand() % 38]); } return targ; } So far I've come up with this, but it does not work (argument of type char is incompatible with parameter of type const char *). Help me find the best solution to my problem. Ty.
strcat() takes a char* as input, but you are giving it a single char instead, thus the compiler error. Also, the buffer that strcat() writes to must be null terminated, but your targ buffer is not null terminated initially, and you are not allocating enough space for a final null terminator anyway. You don't need to use strcat() at all. Since you are looping anyway, just use the loop counter as the index where to write in the buffer: Also, you are using the wrong integer value when modulo the return value of rand(). You are producing a random index that may go out of bounds of your ab[] array. Try this instead: char *randomGet(int num) { srand(time(NULL)); static const char ab[] = "0123456789ABCDEFGHIGKLMNOPQRSTUVWXYZ"; //Alphabet&Digit char *targ = new char[num+1]; for (int i = 0; i < num; ++i) { targ[i] = ab[rand() % 36]; } targ[num] = '\0'; return targ; }
I'd make two changes. First, make the internal source array static: static const char ab[] = "0123456789ABCDEFGHIGKLMNOPQRSTUVWXYZ"; Note that this version does not specify the array size; the compiler will figure it out from the initializer. Second, pass in a pointer to the target array: void randomGet(char* targ, int num) { static const char ab[] = "0123456789ABCDEFGHIGKLMNOPQRSTUVWXYZ"; for (int i = 0; i < num - 1; ++i) targ[i] = ab[rand() % (sizeof ab - 1)]; targ[num - 1] = '\0'; } This way, the caller decides how to allocate memory for the string.
c++ passing array through function [duplicate]
This question already has answers here: Closed 10 years ago. Possible Duplicate: Sizeof an array in the C programming language? I've been fiddling with C to become better acquainted with it and think I may have stumbled upon a initialization/pointer issue that I'm unsure of how to resolve. The below program is an implementation of ROT13, so it takes an input string, and shifts each letter by 13, resulting in the cipher text. The output of my program displays the correct shift, but it won't work for more than 4 characters, making me wonder if sizeof is being used incorrectly. Any other suggestions are appreciated, I'm sure I've messed a few things up at this point. #include <stdio.h> #include <string.h> void encrypt(char *); int main(void){ char input[] = "fascs"; encrypt(input); return 0; } void encrypt(char *input){ char alphabet[] = "abcdefghijklmnopqrstuvwxyz"; printf("Input: %s \n", input); int inputCount = sizeof(input); printf("Characters in Input: %i \n\n", inputCount); //holds encrypted text char encryptedOutput[inputCount]; //Initialize counters int i, j = 0; // loop through alphabet array, if input=current letter, shift 13 mod(26), // push result to output array, encryptedOutput for(i = 0; i < inputCount; i++){ for(j = 0; j < 26; j++){ if(input[i] == alphabet[j]){ encryptedOutput[i] = alphabet[(j + 13) % 26]; } } } //Nul Termination for printing purposes encryptedOutput[i] = '\0'; printf("Rot 13: %s \n\n", encryptedOutput); }
sizeof() in encrypt will not behave as you want it to. Inside encrypt, the sizeof(char *) is 4(on a 32bit machine) or 8(on a 64 bit machine), which you can see is the size of a pointer. To get the sizeof(input) you must change sizeof to strlen. Hence solution = strlen(input) Why this happens?? when you pass an array into a function, that array is internally represented as a pointer. At the called-function's end input is just a pointer, which gives either 4 or 8 bytesize depending upon your machine. To get the sizeof of input, just use a macro like this: #define SIZEOF(x) (sizeof(x)/sizeof(x[0])) and use this in the function that defines x. In your program, x is input in main()
sizeof returns the size of the type of its argument. It cannot determine how many characters are in a pointer to a character array. You should consider using the strlen function if you know that your string is null-terminated.
input has type char* (read as "pointer to char"). sizeof(input) gives you the size of the pointer. You probably want to use strlen to find the length of the string, or pass the length in to the function as an additional argument.
This line causes your problem. int inputCount = sizeof(input); sizeof only determines the size of the variable in this case char *. And every pointer has the size of 4 bytes on a 32 bit system. You can't determine the size of an array during runtime. You could either * pass the size of the input as an parameter * because in your case it is a string, use the strlen in string.h to get the length of the string if the string is terminated by \0. But in both cases you can't simply allocate the output buffer using char output[variable_containing_size]; You would need to use malloc() to dynamically allocate memory during runtime or even easier pass the output parameter as parameter to your function. #include <stdio.h> #include <string.h> #define BUFFER_LENGTH 80 void encrypt(const char * input, char *output); int main(void){ char input[BUFFER_LENGTH] = "fascs"; char output[BUFFER_LENGTH] = {0}; // initialize every field with \0 encrypt(input, output); return 0; } void encrypt(const char *input, char *output){ char alphabet[] = "abcdefghijklmnopqrstuvwxyz"; printf("Input: %s \n", input); int inputCount = strlen(input); printf("Characters in Input: %i \n\n", inputCount); //Initialize counters int i, j = 0; // loop through alphabet array, if input=current letter, shift 13 mod(26), // push result to output array, output for(i = 0; i < inputCount; i++){ for(j = 0; j < 26; j++){ if(input[i] == alphabet[j]){ output[i] = alphabet[(j + 13) % 26]; } } } //Nul Termination for printing purposes output[i] = '\0'; printf("Rot 13: %s \n\n", output); } But in this case the encrypt() function does no size checks at all, and if you're not careful this could easily lead to buffer overflows.
Variables being overwritten when using new
I'm having a problem with dynamic memory allocations in c++. I have to write a function that solves a maze stored in a .dat file. The walls are made of # separated by a space, and some points are words that need to be read in to an arbitrary length c string. This c string is then stored in the maze array. My problem is that my c strings keep overwriting previous ones in memory. How can I tell the program not to overwrite certain blocks of memory? This is the function the initialises the maze array: int LoadMaze(Maze& maze, int& width, int& height, char fname[]) { ifstream ifs(fname); int stringLength; char inputChar; char* newCString; if (ifs.good()) { ifs >> width >> height; maze = new char*[width*height]; for (int i=0;i<width*height;i++) { stringLength = 0; inputChar = '1'; while(inputChar != ' ') { inputChar = ifs.get(); if(inputChar != ' ' && inputChar != '\n') { newCString = resizeChar(newCString, stringLength); newCString[stringLength++] = inputChar; } } //maze = resizeMaze(maze, i); maze[i] = newCString; } ifs.close(); return 1; } else { cerr << "File not found." << endl; return 0; } } Since the C string has to be an arbitrary length, resizeChar increases the cstring size by one. Then the pointer to that cstring is stored in maze. char* resizeChar(char* stringStart, int oldSize) { int counter = 0; char* tempPtr = new char[oldSize + 1]; for(counter = 0; counter < oldSize; counter++) { *(tempPtr + counter) = *(stringStart + counter); } delete[] stringStart; return (tempPtr); }
You are passing an uninitialized value to your function: char* newCString; .... newCString = resizeChar(newCString, stringLength); To fix this you need to give newCString a sensible initial value, and make sure that resizeChar can handle that scenario. It would be better to initialize newCString each time around the loop. That also avoids the problem that you are using the same buffer for every row of the maze. Another major problem is that you never null-terminate the strings you are building. So once you have gone maze[i] = newCString;, that row is just pointing to some characters but you have lost the information of how many characters are in the string. And if you try to output this string then you will buffer overflow and start outputting garbage. You need to allocate 1 more byte than the number of characters in the string, and make the last one of those be '\0'.
The question is how do I stop new values of newCString from being written in the same memory location as previous ones? If you replace the old value of a variable with a new one, then the old value will be overwritten because a variable, during its life, does not move in memory. If you don't want to change the value, simply don't write code that changes it. Set the value of newCString to the value you want it to hold and do not change its value from then one.
initialize character array on the fly
I want to initialize a char array using pointers, on the fly.That is user giving input do not know the size of array.User keeps on giving input until return is pressed.Condition here is to: Use pointers to initialize Not to pass size of array in advance.
Assuming a C question, how about (untested): char *arr = malloc(10); size_t size = 10, index = 0; int ch; while ((ch = getc(stdin)) != EOF && ch != '\n' && ch != '\r') { if (index >= size) { size *= 2; arr = realloc(arr, size); /* XXX check it first. */ } arr[index++] = ch; } arr[index] = 0; If it's really a C++ question you want std::getline with a std::string.
The std::string has a method push_back also std::vector would do the job. Still if you are REALLY forced to use a dynamic array and char pointers I would advice you to implement reallocation strategy similar to the one used in vector - double the size each time the number of elements is more then the current size.
Extract a Byte C++
I have int chop (char* input, unsigned int length) { for (int chopper = 0; chopper < = length; chopper++) { //how to pass 1byte this input to another function //Will this for loop help? } } How do I extract one byte of from this input for my further processing? Thank you
int chop (char* input, unsigned int length) { for (int chopper = 0; chopper < = length; chopper++) { doSomething(input[chopper]); } }
What's wrong with for (int chopper = 0; chopper < length; chopper++) { //how to pass 1byte this input to another function //Will this for loop help? unsigned char byte = input[chopper]; /// do whatever with the byte, and then move on to the next one } ? Note, that chopper < = length is probably wrong, you most likely want chopper < length.
You can treat the pointer as a read-only array, so you'd refer to a single char of your input like this: input[chopper] You should also probably change the loop's end condition to chopper < length as otherwise your loop's last iteration will refer to a memory location beyond input's size (you start from 0).