strcpy to multi-dimensional array in C++ - c++

I've been having issues attempting to copy a word into a multi-dimensional array.
Here is the code I use to create the array:
char *word_buffer;
char *return_result[64];
int buffer_count = 0;
int word_start = 0;
int word_end = 0;
// Some extra, irreverent code.
for (int i = 0; i < length; i += 1) {
if (text[i] == delim) { // Delim is a value such as '\n'
word_end = i;
word_buffer = (char*) malloc(sizeof(char)*64);
strncpy(word_buffer, text + word_start, word_end - word_start); // Copy the word into word_buffer
strcpy(*(return_result + buffer_count), word_buffer);
word_start = i + 1;
}
}
I believe my issue lies with the last line. I attempt to give strcpy a pointer to the address of the 2d array where I want the result of word_buffer to be place. However, this results in a Segmentation Fault.
The goal is to have an array of words returned. I.E.
char *result[10] = { "foo", "bar", "x", "y", "z" };
But to have this done dynamically with code. My code to split the words is working fine. Though, I don't know how to place the value into a 2d array.
Edit: User SHR recommended I try replacing the strcpy line with return_array[buffer_count]=word_buffer;. This does partially work but it crashes after a random amount of values in the array every time. I don't really see how this could be due to high memory usage. Tracking the memory usage of the binary shows nothing out of the ordinary.

Related

Calling free() sometimes causes program to crash

The code below ask the user to input 10 pairs of artist and titles which can be up to 30 characters long. Everything seems to work fine with allocating the space and printing the data back out. The problem only occurs when I try to free the memory at then end and then only if one of the elements is 4 or more characters long. I suspect I am not allocating the memory correctly but I just can't see it.
// Songs.cpp : This file contains the 'main' function. Program execution begins and ends there.
//
// Experimenting with pointers, structures and dynamic allocation of memory
//
#ifdef _MSC_VER
#define _CRT_SECURE_NO_WARNINGS
#endif
#include <iostream>
#include <stdio.h>
struct songInfo
{
char* pArtist; // char pointer for Artist data
char* pTitle; // char pointer for Title data
};
// function prototype declarations
void getSongInfo(struct songInfo *songData, char *Artist, char *Title);
void printSongInfo(songInfo *songData);
int main()
{
struct songInfo songData[10]; // setup array of 10 elements of the structure SongInfo
char sArtist[31];
char sTitle[31];
// prompt user for the artist and title 10 times once for each array element
for (int i = 0; i < 10; i++) {
printf("Artist %i: ", i + 1);
fgets(sArtist, 31, stdin);
strtok(sArtist, "\n"); // trim out return character
printf("Title %i: ", i + 1);
fgets(sTitle, 31, stdin);
strtok(sTitle, "\n"); // trim out return character
getSongInfo(&songData[i], sArtist, sTitle); // allocates the memory and stores the data into the pointer location
}
printSongInfo(songData); // printout the song data stored in the array
// free up the allocated memory space
for (int i = 0; i < 10; ++i) {
free(songData[i].pArtist);
free(songData[i].pTitle);
}
return 0;
}
void getSongInfo(struct songInfo *songData, char *Artist, char *Title) {
songData->pArtist = (char*)malloc(sizeof(Artist) + 1); // Allocate enough memory to hold the string and the null terminator
songData->pTitle = (char*)malloc(sizeof(Title) + 1);
strcpy(songData->pArtist, Artist); // Copy the data into the allocated memory location
strcpy(songData->pTitle, Title);
}
void printSongInfo(songInfo *songData) {
printf("\n%-35s %-35s\n", "Artist", "Title");
printf("%-35s %-35s\n", "-----------------------------------", "-----------------------------------");
for (int i = 0; i < 10; i++) { // iterate through the array of elements
printf("%-35s %-35s\n", songData[i].pArtist, songData[i].pTitle);
}
}
It's not free() call that is invalid, it's malloc.
If you'd print out sizeof(Artist) + 1, you'd likely get either 5 or 9 (depending on your computer architecture). And the same for Title. You check the size of pointer on your machine, which is constant, not the size of array you received.
Undefined Behvaiour means your code may do anything, including "working for now, but will break later at a correct place". You invoke UB by calling strcpy, which tries to copy data into buffer too short to contain the whole string.
You have to pass the size of array to function or calculate it using strlen inside function (and pray that the string is actually null-terminated).
void getSongInfo(struct songInfo *songData, char *Artist, char *Title) {
songData->pArtist = (char*)malloc(strlen(Artist) + 1); // Allocate enough memory to hold the string and the null terminator
songData->pTitle = (char*)malloc(strlen(Title) + 1);
strcpy(songData->pArtist, Artist); // Copy the data into the allocated memory location
strcpy(songData->pTitle, Title);
}
Use std::char_traits::length or strlen. Instead of length of the array, sizeof(Artist) gives you how many bytes a char * pointer occupies.
songData->pArtist =
(char*)malloc(std::char_traits<char>::length(Artist) +
1); // Allocate enough memory to hold the string and the null terminator
songData->pTitle =
(char*)malloc(std::char_traits<char>::length(Title) +
1); // Allocate enough memory to hold the string and the null terminator
Just a side note: using std::string and smart pointers such as std::unique_ptr and std::shared_ptr would save you lots of troubles dealing with memory issues. Overall, using modern c++ will help you write safer code more efficiently.

How to copy std::vector<std::string> to GPU device with CUDA

I'm reading lines from a file, and want to perform some computation on each row by the GPU.
The problem that I'm facing is that up until now I used to copy an array of int in a constant size, now I have a vector of strings and each of them in a different size. I'm using:
std::vector<std::string> lines;
I have used a constant size to copy array. something like:
err = cudaMemcpy(_devArr, tmp, count * sizeof(unsigned int) * 8, cudaMemcpyHostToDevice);
But I'm not sure I fully get the idea how can it worked with vectors. How can I address and copy Vector of Strings? can I somehow copy it and still access it like an array with a thread+block index?
*Using the latest CUDA 10.2 and CUDA RTX 2060 graphic card
You need to flatten the strings down into a contiguous block of memory containing all the strings. My recommendation is to do it with two (total) blocks, one containing the combined string data, and one containing indexes for each of these strings.
std::string combined; //Works perfectly fine so long as it is contiguously allocated
std::vector<size_t> indexes; //You *might* be able to use int instead of size_t to save space
for(std::string const& line : lines) {
combined += line;
indexes.emplace_back(combined.size());
}
/* If 'lines' initially consisted of ["Dog", "Cat", "Tree", "Yard"], 'combined' is now
* "DogCatTreeYard", and 'indexes' is now [3, 6, 10, 14].
*/
//I'm hoping I am writing these statements correctly; I don't specifically have CUDA experience
err = cudaMemcpy(_devArr, combined.data(), combined.size(), cudaMemcpyHostToDevice);
err = cudaMemcpy(_devArr2, indexes.data(), indexes.size() * sizeof(size_t), cudaMemcpyHostToDevice);
Then, in the device itself, you'll be able to read each string as you need them. I'm unfamiliar with the syntax that CUDA employs, so I'm going to write this in OpenCL syntax instead, but the principles should cleanly and directly translate over to CUDA; someone correct me if I'm mistaken.
kernel void main_func(
global char * lines, //combined string data
global ulong * indexes, //indexes telling us the beginning and end of each string
ulong indexes_size, //number of strings being analyzed
global int * results //space to return results back to Host
) {
size_t id = get_global_id(0);//"Which String are we examining?"
if(id >= indexes_size) //Bounds Checking
return;
global char * string; //Beginning of the string
if(id == 0) //First String
string = lines;
else
string = (lines + indexes[id-1]);
global char * string_end = (lines + indexes[id]); //end of the string
for(; string != string_end; string++) {
if(*string == 'A') {
results[id] = 1; //We matched the criteria; we'll put a '1' for this string
return;
}
}
results[id] = 0; //We did not match. We'll put a '0' for this string
}
The results of this code, executed on the initial list of strings, is that for any string that contains an A, it will get a result of 1; if it does not, it gets a result of 0. The logic here should be cleanly transferable to the particular syntax that CUDA uses; let me know if it is not.

How can I find the size of a (* char) array inside of a function?

I understand how to find the size using a string type array:
char * shuffleStrings(string theStrings[])
{
int sz = 0;
while(!theStrings[sz].empty())
{
sz++;
}
sz--;
printf("sz is %d\n", sz);
char * shuffled = new char[sz];
return shuffled;
}
One of my questions in the above example also is, why do I have to decrement the size by 1 to find the true number of elements in the array?
So if the code looked like this:
char * shuffleStrings(char * theStrings[])
{
//how can I find the size??
//I tried this and got a weird continuous block of printing
int i = 0;
while(!theStrings)
{
theStrings++;
i++;
}
printf("sz is %d\n", i);
char * shuffled = new char[i];
return shuffled;
}
You should not decrement the counter to get the real size, in the fist snippet. if you have two element and one empty element, the loop will end with value , which is correct.
In the second snippet, you work on a pointer to a pointr. So the while-condition should be *theStrings (supposing that a NULL pointer ist the marker for the end of your table.
Note that in both cases, if the table would not hold the marker for the end of table, you'd risk to go out of bounds. Why not work with vector<string> ? Then you could get the size without any loop, and would not risk to go out of bounds
What you are seeing here is the "termination" character in the string or '\0'
You can see this better when you use a char* array instead of a string.
Here is an example of a size calculator that I have made.
int getSize(const char* s)
{
unsigned int i = 0;
char x = ' ';
while ((x = s[i++]) != '\0');
return i - 1;
}
As you can see, the char* is terminated with a '\0' character to indicate the end of the string. That is the character that you are counting in your algorithm and that is why you are getting the extra character.
As to your second question, seem to want to create a new array with size of all of the strings.
To do this, you could calculate the length of each string and then add them together to create a new array.

Why does my array element retrieval function return random value?

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.

How to push char array? [duplicate]

This question already has answers here:
Closed 11 years ago.
Possible Duplicate:
How do I use arrays in C++?
I have no idea how to push a char array.
For example if i have "HI.MY.NAME.IS" in a char array,
I would like to put one char in the middle and push the char's right to it.
So it would be something like "HI.MY.SLAME.IS" or something like that.
Any possible solutions?
Use string::insert.
std::string s("test");
s.insert(s.begin()+2, 'c');
There is no "automatic" push which relocates elements in an array. At the lowest levels, there is only read from an array element and write to an array element.
That means you need to copy each element after the insert "one index" down the array. Then you need to set the "inserted" value at its inserted index.
Library routines will do this for you without you noticing; however, you should be aware of the underlying mechanism. Otherwise, you might fall under the impression that inserting into arrays at arbitrary indexes is cheap (when it usually isn't).
//This allocates new memory that you receive responsibility for freeing after use.
char *push(char *charArray, char *charsToPush, int pushPos) {
char *thePushed = new char[strlen(charArray) + strlen(charsToPush) + 1];
memcpy(thePushed, charArray, pushPos);
memcpy(thePushed + pushPos, charsToPush, strlen(charsToPush));
memcpy(thePushed + pushPos + strlen(charsToPush), charArray + pushPos, strlen(charArray) - pushPos);
thePushed[strlen(charArray) + strlen(charsToPush)] = '\0';
return thePushed;
}
To do that you'd have to:
Create a new array that is large enough to hold the original and the new items. Arrays cannot be resized.
Copy all items from the old to the new array, leaving the places for the new characters open.
Insert the new characters.
This is quite complex. But C++ offers a simpler way - std::string:
#include <string>
#include <iostream>
int main() {
std::string text = "HI.MY.NAME.IS";
std::string new_text = text.substr(0, 6) + "SL" + text.substr(7, 6);
std::cout << new_text << std::endl;
}
This program prints HI.MY.SLAME.IS. Or, even better, use insert, as #rasmus suggests.
If you are limited to c-strings or require it to be replaced in-buffer, then you can do something like the below, but your buffer must be large enough to hold the modified string since it's pushing all characters down. That said, you'd be much better off using the std::string as the others suggest.
// ASSUMES buffer is large enough to store one more char
void insertAt(char* buffer, char insertMe, size_t at)
{
size_t len = strlen(buffer);
if (at <= len)
{
memcpy(buffer + at + 1, buffer + at, len - at + 1);
buffer[at] = insertMe;
}
}
char* string = (char*) malloc(14);
string = "HI.MY.NAME.IS";
realloc(string, 15);
for (int i = 14; i > 5; --i) {
string[i+1] = string[i];
}
string[5] = 'S';
string[6] = 'L';
Here you go...lol