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;
Related
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.
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);
I have a CGI application I've been writing in Visual Studio Express 2013, but I've encountered a scenario where the program fails when the string passed into a function is more than 31 bytes. I would try to debug it myself, but everything works fine in Visual Studio Debugger, it's only in Command Prompt where I see the error.
I believe this to be the way that I've allocated(or not allocated) the memory. I have a function which takes in a string and returns the decoded string.
I've stripped everything down to just that function and main so you can see two cases, one which works in CMD and one which fails.
Here's the file:
#include <ctype.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
/*
* Function: urlDecode
* Purpose: Decodes a web-encoded URL
* Input: const char* str - the URL to decode
* Output: char* - the decoded URL
*/
char *urlDecode(const char *str) {
int d = 0; /* whether or not the string is decoded */
char *dStr = malloc(strlen(str) + 1);
char *eStr = malloc(2); /* a hex code */
strcpy(dStr, str);
while (!d) {
d = 1;
int i; /* the counter for the string */
int j = strlen(dStr);
for (i = 0; i<j; ++i) {
if (dStr[i] == '%') {
if (dStr[i + 1] == 0)
return dStr;
if (isxdigit(dStr[i + 1]) && isxdigit(dStr[i + 2])) {
d = 0;
//combine the next two numbers into one
eStr[0] = dStr[i + 1];
eStr[1] = dStr[i + 2];
//convert it to decimal
long int x = strtol(eStr, NULL, 16);
//remove the hex
memmove(&dStr[i], &dStr[i + 2], strlen(dStr) - 1);
dStr[i] = x;
j = j - 2;
}
}
}
}
free(eStr);
return dStr;
}
int main(void)
{
//this one runs fine from command prompt
char *test1 = "s=W3%20%3A%20SVC&action=stop";
printf("%s\n", test1);
char *decoded1 = urlDecode(test1);
printf("%s\n", decoded1);
free(decoded1); //and I can even free the memory
//this one prints in command prompt, but the program crashes immediately after
char *test2 = "service=W3%20%3A%20SVC&action=stop";
printf("%s\n", test2);
char *decoded2 = urlDecode(test2);
printf("%s\n", decoded2);
//when I comment this free out, it debugs fine in VS, but still fails in cmd
//this is the reason I believe it's a memory error
//free(decoded2);
system("PAUSE"); //so I can see what's happening
return 0;
}
You failed to null-terminate eStr, and you did not allocate enough memory for it: you need three characters, not two.
Since eStr is so short, consider making it a stack variable, rather than allocating it on the dynamic store:
char eStr[] = "00";
This would allocate enough space, and make it unnecessary to free the pointer at the end of your function.
Another issue is memmove: it looks like your indexes are off. You could fix it, but it's much easier to avoid memmove altogether: rather than making substitutions in place, use str as your source, and dStr as your destination:
char *urlDecode(const char *str) {
int d = 0; /* whether or not the string is decoded */
char *dStr = malloc(strlen(str) + 1);
char *ret = dStr;
char eStr[] = "00";
strcpy(dStr, str);
while (!d) {
d = 1;
int i; /* the counter for the string */
int j = strlen(dStr);
for (i = 0; i<j; ++i) {
if (str[i] == '%') {
if (str[i + 1] == 0) {
break;
}
if (isxdigit(str[i + 1]) && isxdigit(str[i + 2])) {
d = 0;
//combine the next two numbers into one
eStr[0] = str[i + 1];
eStr[1] = str[i + 2];
//convert it to decimal
long int x = strtol(eStr, NULL, 16);
*dStr++ = x;
}
} else {
*dStr++ = str[i];
}
}
}
*dStr = 0;
return ret;
}
Demo.
should be
char *eStr = calloc(3,1); /* a hex code */
memmove(&dStr[i+1], &dStr[i + 3], strlen(&dStr[i+3])+1 );
#include <stdio.h>
int strLength(char *strP)
{
int i = 0;
while(*(strP + i) != '\0') i++;
return i;
}
// insert the second string into the first starting
// at the specified index
// if failure, do nothing
void insertString(char *str1P, char *str2P, int index)
{
int i = 0,
str1Length = strLength(str1P), str2Length = strLength(str2P);
*(str1P + str1Length + str2Length) = '\0';
while(i < (str1Length - index))
{
*(str1P + index + str2Length + i) = *(str1P + index + i);
*(str1P + index + i) = *(str2P + i);
i++;
}
}
int main()
{
//insert
char str8[20] = "the wrong son";
insertString(str8, "per", 14 );
printf("\nAfter insert1 = %s\n", str8);
insertString(str8, "per", 10 );
printf("After insert2 = %s\n", str8);
insertString(str8, "You are ", 0);
printf("After insert3 = %s\n\n", str8);
return 0;
}
I am learning about pointers and strings in C for my Algorithms and Program Design class, and we were recently given this as part of an assignment. I have everything else complete, but I am still having trouble with the insertString function. The first two calls from main produce a desirable result, but the third seems to break. Could someone help me find what could be causing this?
The third call fails beacuse the size of str8 is 20. and third string insertion needs more memory than that allocated to str8[20].
So allocate more memory to support third string insertion or you can use dynamic allocation to string variable to have a general solution.
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.