what happens when i use malloc() twice in the same pointer? - c

I write a code to split string by delimiter.
I want the function get a string and return its strings divided.
It actually works except for one thing.
when I give string "test", it works.
but when I give string "1234 4567", I can access the value '4567', but not '1234'. (garbage value.)
also "1234 2345 3456 ..." results garbage value in only first argument '1234'.
I thought that using malloc() twice causes problem in the same pointer, but it doesn't.
What is the problem for my codes?
char **ft_set_char(char *str)
{
int i;
int j;
int k;
char *str_c;
char **ret;
k = 0;
j = 0;
ret = (char **)malloc(10);
str_c = (char *)malloc(5);
i = 0;
while (*(str + i) != '\0')
{
if (*(str + i) == ' ')
{
*(str_c + k) = '\0';
k = 0;
*(ret + j) = str_c;
j++;
i++;
str_c = (char *)malloc(5);
}
*(str_c + k) = *(str + i);
i++;
k++;
}
*(str_c + k) = '\0';
*(ret + j) = str_c;
*(ret + j + 1) = NULL;
return (ret);
}

ret = (char **)malloc(10);
That is not correct because it allocates 10 bytes and not 10 char * elements. It should be:
ret = malloc(10 * sizeof *ret);
Other unrelated issues but should be noted for best practice:
Don't cast the result of malloc
Don't use magic numbers like 10 and 5. For the former at least use a #define MAX_ARRAY_SIZE 10. For the latter, you can keep work out the exact size of the string to be copied from the original str - that will make your code more robust in case it is ever used with longer sub-strings.

Related

Create a string from a vector of integers in C

I'm trying to create a string from a vector, something like this:
int vector[3] = {1, 2, 3}.
Then, the string I would get should be:
[1, 2, 3] stored in some char[] variable.
I tried to do it dynamically like follows:
void print_vector(int *vector, int lon){
char *str = (char*)calloc(3*lon, sizeof(char));
str[0] = "[";
str[1] = (char) vector[0];
for(int i = 1; i < lon; i += 3){
str[i] = (char)vector[i];
if(i != lon - 1){
str[i + 1] = (char)",";
str[i + 2] = " ";
}else{
str[i + 1] = "]";
}
}
printf("%s\n", str);
}
Where lon is the length of the vector, but I'm getting this warning from the compiler:
warning: the assignment to "char" from "char *" creates an integer from a pointer without a conversion [-Wint-conversion]
What am I doing wrong? Thanks.
There are several issues with your code -
You are using " instead of '. " is used to create a string literal which is of type char*. Hence the error you are getting.
(char) vector[0]; is not the right way to convert an integer to strings. You should use something like sprintf.
You haven't allocated enough memory with the call to calloc (the brackets, commas, space, nul-terminator).
You are only filling in certain characters in the buffer. The rest are initialized to 0. This will cause the string to terminate earlier than expected.
To start, you can fix your code as -
void print_vector(int *vector, int lon){
char *str = calloc(5*lon+3, sizeof(char));
// 5 for each character (3 characters per integer + space + comma.
// Two brackets and nul-terminator
strcpy(str, "[");
if (lon) {
sprintf(str+1, "%d", vector[0]);
for(int i = 1; i < lon; i++){
sprintf(str + strlen(str), ", %d", vector[i]);
}
}
strcat(str, "]");
printf("%s\n", str);
}
You can find the working demo here on ideone.
You're trying to assign strings to char array elements. You need to use single quotes to create char constants.
So
str[0] = "[";
should be
str[0] = '[';
and similarly for all the other assignments.
Another problem is that (char)vector[i] will not return the character representation of the number in vector[i]. It simply uses the integer as the character code. So if vector[i] is 1, this produces '\1', not '1'. The way to get the character representation of a number is with '0' + vector[i].
Finally, you need to add a null terminator to the end of the string so you can print it with %s formatting. And you should free it before returning to prevent a memory leak.
Other problems: You're only putting every 3rd element of vector into the string. You need to use separate indexes for vector and str. And array indexes start at 0, not 1.
void print_vector(int *vector, int lon){
char *str = (char*)calloc(3*lon, sizeof(char));
str[0] = "[";
str[1] = (char) vector[0];
for(int i = 0; i < lon; i++){
str[i*3] = '0' + vector[i];
if(i != lon - 1){
str[i*3 + 1] = ',';
str[i*3 + 2] = ' ';
}else{
str[i*3 + 1] = ']';
str[i*3 + 2] = '\0';
}
}
printf("%s\n", str);
}
Assuming every element in your vector is one digit, and every element is spaced identicially...
... and remembering you need to allicate a null byte at the end to terminate your string...
... perhaps something like this (uncompiled/untested):
void print_vector(int *vector, int lon){
char *str = (char*)calloc((3*lon)+1, sizeof(char));
char *s = str;
*s++ = "[";
int i=1;
while (i < lon) {
*s++ = vector[i] + 0x30; // ASCII "0"= 0x30, "1"= 0x31, ...
*s++ = ',';
*s++ = ' ';
i++;
}
s -= 2;
*s++ = ']';
*s++ = 0;
printf("%s\n", str);

Pointer Declaration vs. Finite Array Declaration in C

I am experimenting with pointer and array declaration in C, and I am seeing results that do not make sense to me. Consider this function that converts binary to base 64:
char *bin2b64Str(char *binStr) {
char finalb64str[256];
char *paddedBin;
int i, r, t, loops;
char buffer[] = { '0', '0', '0', '0', '0', '0', '\0' };
int count = 0;
r = 6 - strlen(binStr) % 6;
if (r != 6) {
loops = (int)strlen(binStr) / 6 + 1;
paddedBin = (char*)malloc(((strlen(binStr) + r) + 1) * sizeof(char));
memmove(paddedBin, &buffer[6 - r], r);
memmove(&paddedBin[r], binStr, strlen(binStr) + 1);
}else{
loops = (int) strlen(binStr) / 6;
paddedBin = (char*)malloc(((strlen(binStr)) + 1) * sizeof(char));
memmove(paddedBin, binStr, strlen(binStr) + 1);
}
char b64str[strlen(binStr) + r + 1];
for (i = 0; i < loops; i++) {
char sextet[7];
++count;
if (count != loops) {
memcpy(sextet, &paddedBin[6 * i], 6);
sextet[6] = '\0';
} else {
memcpy(sextet, &paddedBin[6 * i], 7);
sextet[6] = '\0';
}
b64str[i] = bin2b64Char(sextet);
}
memcpy(finalb64str, b64str, loops);
finalb64str[loops] = '\0';
return finalb64str;
}
This code works just fine for me, but if I instead change the first line to:
char *finalb64str
and replace the last memcpy line with:
finalb64str = b64str;
it fails miserably! I don't understand at all. Why is this happening? I have been researching all about pointers and arrays, but nothing I've found seems to answer this for me.
char b64str[strlen(binStr)+r + 1];
is an array allocated on the stack which is local to the function, any references to it when the function has returned are invalid.
when you write
finalb64str = b64str;
at the end you are just assigning the local variable to the array that is declared locally, the address returned will be invalid.
in order to make b64str visible on the outside it easiest if you malloc the storage and then return the pointer to that.
char* b64str = malloc(strlen(binStr)+r + 1);
...
return b64str;

How to append a character onto a string?

The examples I've seen on Stack Overflow come close to what my problem is but none of them seem to match, so I have to ask myself: How can I properly append a character to a string in C? I am aware that strcat() does not do the job, nor does using array values work properly. Here is my code:
char* buildWord(int posX, int posY, int nextX, int nextY, int gridX, int gridY, char** grid, char* str, int length){
int len2;
char* word = malloc(sizeof(char) * 20);
if(posX+nextX < 0 || posX+nextX > gridX)
return NULL;
if(posY+nextY < 0 || posY+nextY > gridX)
return NULL;
strcpy(word, str);
len2 = strlen(word);
word[len2 + 1] = grid[posX + nextX][posY + nextY]; //grid[x][y] represents a
word[len2 + 2] = '\0'; //single character
printf("%s", word);
length++;
if(length < 4)
word = buildWord(posX+nextX, posY+nextY, nextX, nextY, gridX, gridY, grid, word, length);
return word;
}
As you might guess, the purpose of this code is to build a string from a grid of letters with a particular direction in mind (similar to a wordsearch). For example, if my initial string "str" is "c" and am going in a diagonal direction where the next letter is "a", the string I want to put together is "ca".
When I run this code, the letter is not appended. The string remains the same throughout the code, which of course causes it to break. Is there a proper method to doing this?
You have a bug here:
word[len2 + 1] = grid[posX + nextX][posY + nextY]; //grid[x][y] represents a
word[len2 + 2] = '\0';
It should be:
word[len2] = grid[posX + nextX][posY + nextY]; //grid[x][y] represents a
word[len2 + 1] = '\0';
Remember that the index begin with 0

Reversing an array in C

I am new to cpp and have a question regarding arrays. The code I have below should create a reversed version of str and have it be stored in newStr. However, newStr always comes up empty. Can someone explain to me why this is happening even though I am assigning a value from str into it?
void reverse (char* str) {
char* newStr = (char*)malloc(sizeof(str));
for (int i=0;i<sizeof(str)/sizeof(char);i++) {
int index = sizeof(str)/sizeof(char)-1-i;
newStr [i] = str [index];
}
}
PS: I know that it is much more efficient to reverse an array by moving the pointer or by using the std::reverse function but I am interested in why the above code does not work.
As above commenters pointed out sizeof(str) does not tell you the length of the string. You should use size_t len = strlen(str);
void reverse (char* str) {
size_t len = strlen(str);
char* newStr = (char*)malloc(len + 1);
for (int i=0; i<len;i++) {
int index = len-1-i;
newStr[i] = str[index];
}
newStr[len] = '\0'; // Add terminator to the new string.
}
Don't forget to free any memory you malloc. I assume your function is going to return your new string?
Edit: +1 on the length to make room for the terminator.
The sizeof operator (it is not a function!) is evaluated at compile time. You are passing it a pointer to a region of memory that you claim holds a string. However, the length of this string isn't fixed at compile time. sizeof(str)/sizeof(char) will always yield the size of a pointer on your architecture, probably 8 or 4.
What you want is to use strlen to determine the length of your string.
Alternatively, a more idiomatic way of doing this would be to use std::string (if you insist of reversing the string yourself)
std::string reverse(std::string str) {
for (std::string::size_type i = 0, j = str.size(); i+1 < j--; ++i) {
char const swap = str[i];
str[i] = str[j];
str[j] = swap;
}
return str;
}
Note that due to implicit conversion (see overload (5)), you can also call this function with your plain C-style char pointer.
There are two issues here:
The sizeof operator won't give you the length of the string. Rather, it gives you the size of a char* on the machine you are using. You can use strlen() instead to get the
A c-string is terminated by a NULL character (which is why strlen() can return the correct length of the string). You need to make sure you are not accidentally copying the NULL character from your source string to the beginning of your destination string. Also, you need to add a NULL character at the end of your destination string or you will get some unexpected output.
#include <bits/stdc++.h>
using namespace std;
vector<string> split_string(string);
// Complete the reverseArray function below.
vector<int> reverseArray(vector<int> a) {
return {a.rbegin(), a.rend()};
}
int main()
{
ofstream fout(getenv("OUTPUT_PATH"));
int arr_count;
cin >> arr_count;
cin.ignore(numeric_limits<streamsize>::max(), '\n');
string arr_temp_temp;
getline(cin, arr_temp_temp);
vector<string> arr_temp = split_string(arr_temp_temp);
vector<int> arr(arr_count);
for (int i = 0; i < arr_count; i++) {
int arr_item = stoi(arr_temp[i]);
arr[i] = arr_item;
}
vector<int> res = reverseArray(arr);
for (int i = 0; i < res.size(); i++) {
fout << res[i];
if (i != res.size() - 1) {
fout << " ";
}
}
fout << "\n";
fout.close();
return 0;
}
vector<string> split_string(string input_string) {
string::iterator new_end = unique(input_string.begin(), input_string.end(), [] (const char &x, const char &y) {
return x == y and x == ' ';
});
input_string.erase(new_end, input_string.end());
while (input_string[input_string.length() - 1] == ' ') {
input_string.pop_back();
}
vector<string> splits;
char delimiter = ' ';
size_t i = 0;
size_t pos = input_string.find(delimiter);
while (pos != string::npos) {
splits.push_back(input_string.substr(i, pos - i));
i = pos + 1;
pos = input_string.find(delimiter, i);
}
splits.push_back(input_string.substr(i, min(pos, input_string.length()) - i + 1));
return splits;
}

Replacing spaces with %20 in C

I am writing a fastcgi application for my site in C. Don't ask why, leave all that part.
Just help me with this problem- I want to replace spaces in the query string with %20.
Here's the code I'm using, but I don't see 20 in the output, only %. Where's the problem?
Code:
unsigned int i = 0;
/*
* Replace spaces with its hex %20
* It will be converted back to space in the actual processing
* They make the application segfault in strtok_r()
*/
char *qstr = NULL;
for(i = 0; i <= strlen(qry); i++) {
void *_tmp;
if(qry[i] == ' ') {
_tmp = realloc(qstr, (i + 2) * sizeof(char));
if(!_tmp) error("realloc() failed while allocting string memory (space)\n");
qstr = (char *) _tmp;
qstr[i] = '%'; qstr[i + 1] = '2'; qstr[i + 2] = '0';
} else {
_tmp = realloc(qstr, (i + 1) * sizeof(char));
if(!_tmp) error("realloc() failed while allocating string memory (not space)\n");
qstr = (char *) _tmp;
qstr[i] = qry[i];
}
}
In the code, qry is char *, comes as a actual parameter to the function.
I tried with i + 3, 4, 5 in realloc() in the space replacer block, no success.
String-handling in C can be tricky. I'd suggest going through the string first, counting the spaces, and then allocating a new string of the appropriate size (original string size + (number of spaces * 2)). Then, loop through the original string, maintaining a pointer (or index) to the position in both the new string and the original one. (Why two pointers? Because every time you encounter a space, the pointer into the new string will get two characters ahead of the pointer into the old one.)
Here's some code that should do the trick:
int new_string_length = 0;
for (char *c = qry; *c != '\0'; c++) {
if (*c == ' ') new_string_length += 2;
new_string_length++;
}
char *qstr = malloc((new_string_length + 1) * sizeof qstr[0]);
char *c1, *c2;
for (c1 = qry, c2 = qstr; *c1 != '\0'; c1++) {
if (*c1 == ' ') {
c2[0] = '%';
c2[1] = '2';
c2[2] = '0';
c2 += 3;
}else{
*c2 = *c1;
c2++;
}
}
*c2 = '\0';
qstr[i] = '%'; qstr[i + 1] = '2'; qstr[i + 2] = '0';
That line writes three characters to your output buffer, so the next character you write needs to be written at qstr[i+3]. However, you only step i by 1, so the next character is written to qstr[i+1], overwriting the '2'.
You will need to keep separate indexes for stepping through qry & qstr.
I agree with David.
It is advisable to do it in two-steps: in the first loop you just count the spaces:
int spaceCounter=0;
const int sourceLen = strlen(qry);
for(int i = 0; i < sourceLen; ++i)
if ( qry[i] == ' ')
++spaceCounter;
char* newString = (char*)malloc(sourceLen + 3*spaceCounter*sizeof(char) + 1)
//check for null!
for(int i = 0; i < sourceLen; ++i)
if ( qry[i] == ' ')
{
*newString++ = '%';
*newString++ = '2';
*newString++ = '0';
}
else
*newString++ = qry[i];
*newString = '\0';
Warning: code not tested.
You are assigning using the same counter I you will need to have 2 counters since the strings have different lengths
your else case assigns qstr[i] = qry[i]; after you have written the %20 you are at least off by 2 on the result string.
This is known as url encode. You can refer to this page to see some similar implementation: http://www.geekhideout.com/urlcode.shtml
char* toHexSpace(const char *s)
{
char *b=strcpy(malloc(3*strlen(s)+1),s),*p;
while( p=strchr(b,' ') )
{
memmove(p+3,p+1,strlen(p));
strncpy(p,"%20",3);
}
return b;
}
needs "free" in calling context.

Resources