I am having issues with filling an array of strings that was created dynamically. The array basically contains two strings and I would like to print them both with their lengths. I am getting a very weird result whereby the memory locations are getting mixed up. Please see the code below.
Any suggestions would greatly be appreciated. Thanks.
void printWords(char **words, int numberOfWords)
{
int index;
for (index = 0; index < numberOfWords; index++)
{
printf("%s, %d\n", &(*words)[index], (int)strlen(&(*words)[index]));
}
}
void fillWords(char **words)
{
*words = malloc(2 * sizeof(char *));
char hello[] = {"Hello"};
(*words)[0] = (char)malloc(strlen(hello) * sizeof(char));
strcpy(&(*words)[0], hello); //Copy word into array
char world[] = {"Worldz"};
(*words)[1] = (char)malloc(strlen(world) * sizeof(char));
strcpy(&(*words)[1], world); //Copy word into array
}
int main (int argc, const char * argv[])
{
char *words;
fillWords(&words);
printWords(&words, 2);
return 0;
}
The expected output should be
Hello, 5
Worldz, 6
however I am getting
HWorldz, 7
Worldz, 6
I think you are getting confused between char * and char **.
Also, be sure to allocate enough memory for the null-termination character at the end of the string.
Here is my solution:
#include <stdio.h>
#include <string.h>
#include <malloc.h>
void printWords(char **words, int numberOfWords)
{
int index;
for (index = 0; index < numberOfWords; index++)
{
printf("%s, %d\n", words[index], (int)strlen(words[index]));
}
}
char ** createWords()
{
char ** words;
// Allocate memory for an array of pointers, length 2.
words = malloc(2 * sizeof(char *));
char hello[] = {"Hello"};
words[0] = malloc((strlen(hello)+1) * sizeof(char));
strcpy(words[0], hello); //Copy word into array
char world[] = {"Worldz"};
words[1] = malloc((strlen(world)+1) * sizeof(char));
strcpy(words[1], world); //Copy word into array
return words;
}
int main (int argc, const char * argv[])
{
char **words;
words = createWords();
printWords(words, 2);
return 0;
}
I renamed fillWords to createWords and made it return a pointer instead of taking a pointer as an argument. If you really want fillWords to take a pointer as an argument, you can do it, but the argument will have to be of type char ***.
First problem: you can't put 2 words in a char * (well ... you can, but not the way you're doing; and the way to do it is nothing like your code).
You need an "array of strings", or, more C-like, an array of char *:
char *words[2]; /* words[0] and words[1] are pointers to char */
char *wrong; /* wrong[0] is a char; wrong[1] is a char */
So, change the definition of words in your main and check/edit all the other functions for correctness.
int main (int argc, const char * argv[])
{
char *words[2];
fillWords(words);
printWords(words, 2);
return 0;
}
Here is the solution. I was getting confused between char* and char. What I want was an array of chars.
void printWords(char **words, int numberOfWords)
{
int index;
for (index = 0; index < numberOfWords; index++)
{
printf("%s, %d\n", words[index], (int)strlen(words[index]));
}
}
void fillWords(char **words)
{
*words = malloc(2 * sizeof(char *));
char hello[] = {"Hello"};
words[0] = malloc(strlen(hello) * sizeof(char));
strcpy(words[0], hello); //Copy word into array
char world[] = {"Worldz"};
words[1] = malloc(strlen(world) * sizeof(char));
strcpy(words[1], world); //Copy word into array
}
int main (int argc, const char * argv[])
{
char *words;
fillWords(&words);
printWords(&words, 2);
return 0;
}
Related
I need write the following function: char * Rev(char * str, int size);
The function get *pointer to string. It should replace the order of words within str, and return the result in the pointer. Only need reverse order for the words. Must use the helper swap function. In this function, there is no use of [] anywhere, ONLY USE pointers. Printing via main only.
#include <stdio.h>
#include <stdlib.h>
int main()
{
char *str1,*str2,*pRev;
char *pstr="YPEFMI ICMKMS JGLYZJ";
swap(&str1, &str2);
getchar();
*pRev =*RevWords (pstr,SIZE)
return 0;
}
methods.c
void swap(char* str1, char* str2);
char * Rev(char * string, int size);
//The function replaces the contents of both strings 1s and 2s.
void swap(char* str1, char* str2)
{
// if both of them are zero characters then stop
if (*str1 == '\0' && *str2 == '\0')
return;
// else swap the contents of the pointers
else
{
char tmp = *str1;
*str1 = *str2;
*str2 = tmp;
// advance both pointer and swap them too if thye are not '\0'
swap(++str1, ++str2);
}
}
char * Rev(char * string, int size)
{ //no idea-->NOT work in reverse.
char string[SIZE * (SIZE + 1)]
char *str = (char *)(malloc (SIZE * SIZE + SIZE-1));
for (int i = 0; i < SIZE; i++) {
memcpy(string + i * SIZE, matrix + i, SIZE);
if (i < SIZE - 1) {
swap(*(string + i * SIZE + SIZE));
} else {
swap(*(string + i * SIZE + SIZE)) = 0;
}
}
return string;
}
The swap method work but REV method NOT work.
For example:
pStr = YPEFMI ICMKMS JGLYZJ
pRev = -->JGLYZJ ICMKMS YPEFMI <--
I am working a function that needs to be re-entrant - the function is given a memory buffer as an argument and should use such buffer for all its memory needs. In other words, it can't use malloc, but rather should draw the memory the supplied buffer.
The challenge that I ran into is how to overlay an array of strings over a char array of given size (the buffer is supplied as char *), but my result is array of strings (char **).
Below is a repro:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define BUFFER_SIZE 100
#define INPUT_ARRAY_SIZE 3
char *members[] = {
"alex",
"danny",
"max"
};
int main() {
// this simulates a buffer that is presented to my func
char *buffer = malloc(BUFFER_SIZE);
char *orig = buffer;
memset(buffer, NULL, BUFFER_SIZE);
// pointers will be stored at the beginning of the buffer
char **pointers = &buffer;
// strings will be stored after the pointers
char *strings = buffer + (sizeof(char *) * INPUT_ARRAY_SIZE);
for(int i = 0; i < INPUT_ARRAY_SIZE; i++) {
strncpy(strings, members[i], (strlen(members[i]) + 1));
// Need to store pointer to string in the pointers section
// pointers[i] = strings; // This does not do what I expect
strings += ((strlen(members[i]) + 1));
}
for (int i=0; i < BUFFER_SIZE; i++) {
printf("%c", orig[i]);
}
// Need to return pointers
}
With the problematic line commented out, the code above prints:
alex danny max
However, I need some assistance in figuring out how to write addresses of the strings at the beginning.
Of course, if there an easier way of accomplishing this task, please, let me know.
Here take a look at this.
/* conditions :
*
* 'buffer' should be large enough, 'arr_length','arr' should be valid.
*
*/
char ** pack_strings(char *buffer, char * arr[], int arr_length)
{
char **ptr = (char**) buffer;
char *string;
int index = 0;
string = buffer + (sizeof(char *) * (arr_length+1)); /* +1 for NULL */
while(index < arr_length)
{
size_t offset;
ptr[index] = string;
offset = strlen(arr[index])+1;
strcpy(string,arr[index]);
string += offset;
++index;
}
ptr[index] = NULL;
return ptr;
}
usage
char **ptr = pack_strings(buffer,members,INPUT_ARRAY_SIZE);
for (int i=0; ptr[i] != NULL; i++)
puts(ptr[i]);
I have an array of pointers to strings.
char **array;
I declare it this way and not char *array[N] because this array won't have a static number of elements.
Declaring the array this way, I will probably have to realloc the sizeof it every time I add a new element (pointer to string).
int main(void)
{
char **array;
char *word = "lolol";
char *word2 = "blabla";
return 0;
}
Could you give me an example on how I should "create space" in the array in order to store pointers to these strings?
The best way of doing it is probably by making a struct
This way, you can resize it, and add as many strings as you want without needing to choose a specific size.
Note: setting the string_array's capacity and size to 0 is necessary for it to work.
You could do it by a function like this instead:
void load_array(string_array *array)
{
array->size = 0;
array->capacity = 0;
}
And call it like this:
load_array(&my_array);
Note, when getting the value from one of these arrays using [], you must call it like this:
my_array.arr[index]
This is because you must refer to the pointer in the array struct, which is as arr (char **)
I have tested the below, and it works perfectly.
# include <stdio.h>
typedef struct string_array
{
char **arr;
unsigned capacity, size;
} string_array;
void add_to_array(string_array *array, char *str)
{
if(array->capacity == 0)
{
array->arr = (char **)malloc((array->capacity = 3) * sizeof(char *));
array->arr[array->size++] = str;
}
else if(array->capacity == array->size)
{
array->arr = (char **)realloc(array->arr, (array->capacity *= 1.5) * sizeof(char *));
array->arr[array->size++] = str;
}
else
{
array->arr[array->size++] = str;
}
}
int main(void)
{
char *str1 = "Hello World";
char *str2 = "Hello World2";
char *str3 = "Hello World3";
char *str4 = "Hello World4";
char *str5 = "Hello World5";
string_array my_array;
my_array.capacity = 0;
my_array.size = 0;
add_to_array(&my_array, str1);
add_to_array(&my_array, str2);
add_to_array(&my_array, str3);
add_to_array(&my_array, str4);
add_to_array(&my_array, str5);
// and so on
for (int i = 0; i < my_array.size; ++i)
{
printf(my_array.arr[i]);
printf("\n");
}
free(my_array.arr);
getchar(); // this means pressing enter closes the console
return (0);
}
Here is a demonstrative program
#include <stdio.h>
#include <stdlib.h>
int main(void)
{
size_t N = 2;
char **array = malloc( N * sizeof( char * ) );
if ( !array ) return 1;
char *word = "lolol";
char *word2 = "blabla";
array[0] = word;
array[1] = word2;
char *word3 = "Hello";
++N;
array = realloc( array, N * sizeof( char * ) );
if ( !array ) return 2;
array[2] = word3;
for ( size_t i = 0; i < N; i++ ) puts( array[i] );
free( array );
return 0;
}
The program output is
lolol
blabla
Hello
Simply allocate some room for pointers in your array, and free it when you're done.
char *word = "lolol";
char *word2 = "blabla";
char** array = malloc(2*sizeof(char*));
array[0] = word;
array[1] = word2;
free(array);
You can change that 2*sizeof(char*) to a N*sizeof(char*) if you want more elements.
I'm trying to write a C function to reverse a passed in C style string (ie char *) and return the char pointer of the reversed string. But when I run this in VS2012, nothing is printed in terminal and "main.exe has stopped working" msg shows up.
#include <stdio.h>
#include <string.h>
char * rrev_str(char * str )
{
char *revd_str=""; //I tried char revd_str []="" error: stack around "revd_str" is corrupted
int i,r;
int str_len=strlen(str);
for (i = str_len-1, r=0; i >=0; i--,r++)
{
revd_str[r]= str[i];
}
return revd_str;
}
int main(int argc, char* argv[])
{
char str1 [] ="STEETS";
char str2 [] ="smile everyday!";
//reverse "chars" in a C string and return it
char * rev_string=rrev_str(str1);
}
The problem here is three fold. First you aren't allocating enough space for the reversed string, and secondly you are returning a pointer to a local variable in rrev_str(), and thirdly you're modifying a string literal. You need to allocate space for revd_str on the heap:
char * rrev_str(char * str )
{
int i,r;
int str_len=strlen(str);
char *revd_str=malloc(str_len + 1);
memset(revd_str, 0, str_len + 1);
for (i = str_len-1, r=0; i >=0; i--,r++)
{
revd_str[r]= str[i];
}
return revd_str;
}
Problem: You are accessing invalid memory address.
revd_str is pointing to literal constant string of length 1 and you are accessing it beyond the length which is invalid.
Solution:
Create char array of require length (statically or dynamically).
Reverse the given string.
Pass 2nd param as destination string
syntax: char * rrev_str(char * src, char *dest);
Reverse the given string
char * rrev_str(char * str )
{
int start = 0;
int end = strlen(str) - 1;
char temp;
for (; start < end; start++ ,end--)
{
temp = str[start];
str[start] = str[end];
str[end] = temp;
}
return str;
}
int main(int argc, char* argv[])
{
char string [] ="smile";
//reverse "chars" in a C string and return it
char * rev_string = rrev_str(string);
printf("%s",rev_string);
}
Pass 2nd param as destination string
char * rrev_str(char * src, char *dest)
{
int srcLength = strlen(src);
int destLength = strlen(dest);
int i;
// Invalid destination string
if (srcLength > destLength)
{
return NULL;
}
dest[srcLength] = '\0';
srcLength--;
for (i=0; srcLength >= 0;i++, srcLength--)
{
dest[i] = src[srcLength];
}
return dest;
}
int main(int argc, char* argv[])
{
char string [] ="smile";
char revString[20];
//reverse "chars" in a C string and return it
char * rev_string = rrev_str(string, revString);
printf("%s",rev_string);
}
What! you are doing..
char *revd_str=""; // Creating String Literal which can't be modified because they are read only
char *revd_str[]=""; // Creating Char Array of Size Zero.
So Solution are
Either take reference of your string
char *revd_str = strdup(str);
Or create dynamic char array
char *revd_str = (char*) malloc (strlen(str)+1);
your program will run fine. logic is incorrect for reversing so modify it. A sample solution is given below
char * rrev_str(char * str )
{
char *revd_str=strdup(str);
int i; // no need for extra 'int r'
int str_len=strlen(str);
for (i = 0; i < str_len/2; i++)
{
char temp = revd_str[i];
revd_str[i]= revd_str[str_len - 1 -i];
revd_str[str_len - 1 -i] = temp;
}
return revd_str;
}
I'm attempting to pass a pointer to a pointer (char**) into a function that will initialize it, and then pass it into another function that will free the memory, however I'm getting seg faults on the freeing which leads me to believe my allocation is going wrong.
Valgrind is reporting use of uninitalized value at this line. tmp[i] is pointing to 0x0.
if(tmp[i]) free((char*)tmp[i]);
Here is the code (this is only test code)
void
alloc_strings(char ***test, int count)
{
char **tmp = *test;
tmp = malloc(count * sizeof(char*));
int i;
for(i = 0; i < count; i++) {
tmp[i] = malloc(6);
strcpy(tmp[i],"Hello");
}
}
void
free_strings(char ***test, int count)
{
char **tmp = *test;
int i;
for(i = 0; i < count; i++) {
if(tmp[i]) free((char*)tmp[i]);
}
if(tmp)
free(tmp);
}
And the invocation:
int
main(int argc, char **argv)
{
char **test;
alloc_strings(&test, 10);
free_strings(&test, 10);
return 0;
}
I have been playing around with this for a while, reading up on pointers etc however can't get my head around the issue. Any thoughts greatly appreciated!
You need to assign to *test, not to assign from it. How about:
void
alloc_strings(char ***test, int count)
{
char **tmp = malloc(count * sizeof *tmp);
/*...*/
*test = tmp;
}
In the code example,
alloc_strings(char ***test, int count)
{
char **tmp = *test;
*test should have some space to store a pointer to char ** which currently is not allocated. Hence, if the example is as this
char** array[1];
alloc_strings(&array[0], 7);
I feel that the code will work.