I am trying to allocate memory for an array of strings using malloc. The size of each string is not known before the input from the user, so this is how I tried to allocate memory for each element in the array.
I have some errors with the code, but can't figure them out or can't understand them. I am getting an error regarding the allocation. Can anyone tell me what's wrong about this?
bool read_strings(char * strings[], int n)
{
int i = 0;
while (i<n)
{
char string[MAX_LENGTH];
if (scanf("%s", string)!=1)
return false;
char* memory= (char*)malloc(sizeof(char)*strlen(string));
if (memory == NULL)
return false;
memory = string;
strings[i] = memory;
i++;
}
return true;
}
Thanks a lot!
At least you have to replace
char* memory= (char*)malloc(sizeof(char)*strlen(string));
if (memory == NULL)
return false;
memory = string;
strings[i] = memory;
by
strings[i] = strdup(string)
Note that using scanf("%s", string) the separator between the read string is the space
The problem is right here:
char* memory = (char*)malloc(sizeof(char)*strlen(string));
memory = string; <<<
strings[i] = memory;
You will lose memory if you assign strings to pointers like this.
Either:
a) Copy the string into the newly allocated memory using strcpy() or strncpy(), also make sure you have enough space for the NULL character \0
strings[i] = (char*)malloc(sizeof(char) * (strlen(string) + 1));
strcpy(strings[i], string);
b) Use strdup(), which is like a mix between strcpy() and malloc(), it creates just enough space for your string and copies it into a new memory location
strings[i] = strdup(string);
You have many mistakes
(char*)malloc(sizeof(char)*(strlen(string) **+ 1**)) . You have to reserve memory to '\0'
Very wrong
memory = string;
To copy strings you have to usr strcpy (the correct function nowadays is strncpy is more safe)
To have a truly unlimited buffer in C, (or limited by the amount of memory and a size_t,) you could build up the memory allocation incrementally.
#include <stdlib.h> /* realloc free */
#include <stdio.h> /* stdin fgets printf */
#include <string.h> /* strcpy */
#include <assert.h> /* assert */
#include <stdint.h> /* C99 SIZE_MAX */
#include <stdbool.h> /* C99 bool */
/* Returns an entire line or a null pointer, in which case eof or errno may be
set. If not-null, it must be freed. */
static char *line(void) {
char temp[1024] = "", *str = 0, *str_new;
size_t temp_len, str_len = 0;
while(fgets(temp, sizeof temp, stdin)) {
/* Count the chars in temp. */
temp_len = strlen(temp);
assert(temp_len > 0 && temp_len < sizeof temp);
/* Allocate bigger buffer. */
if(!(str_new = realloc(str, str_len + temp_len + 1)))
{ free(str); return 0; }
str = str_new;
/* Copy the chars into str. */
strcpy(str + str_len, temp);
assert(str_len < SIZE_MAX - temp_len); /* SIZE_MAX >= 65535 */
str_len += temp_len;
/* If on end of line. */
if(temp_len < sizeof temp - 1 || str[str_len - 1] == '\n') break;
}
return str;
}
static bool read_strings(char * strings[], int n) {
char *a;
int i = 0;
while(i < n) {
if(!(a = line())) return false;
strings[i++] = a;
}
return true;
}
int main(void) {
char *strings[4] = { 0 }; /* C99 */
size_t i;
bool success = false;
do {
if(!read_strings(strings, sizeof strings / sizeof *strings)) break;
for(i = 0; i < sizeof strings / sizeof *strings; i++)
printf("%lu: <%s>\n", (unsigned long)i, strings[i]);
success = true;
} while(0); {
for(i = 0; i < sizeof strings / sizeof *strings; i++)
free(strings[i]);
}
return success ? EXIT_SUCCESS : (perror("stdin"), EXIT_FAILURE);
}
I think that's right-ish. However, this should bring pause; what if they never hit enter? If one has a MAX_LENGTH, then consider allocating statically, depending on your situation.
Edit: It also has a worst-case running time that may not be desirable; if entering really arbitrarily large lines, use a geometric progression to allocate space.
I think this is what you wanted to do:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int read_strings(char * strings[], int n)
{
int i = 0;
char buffer[256] ={0}; /*a temp buffer of fixed max size for input */
if(NULL == strings)
{
return 0 ;
}
for (i= 0; i<n; ++i)
{
if (fgets(buffer, 256,stdin)== NULL) /*safer then scanf - read input into the buffer*/
return 0;
strings[i]= malloc(sizeof(char)*(strlen(buffer)+1)); /* the char poiner in he i place will now point to the newly allocated memory*/
strcpy(strings[i], buffer); /*copy the new string into the allocated memory now string[i] is pointing to a string*/
}
return 1;
}
static void printStringsArray(const char* strArr[], size_t size)
{
int i = 0;
if(NULL == strArr)
{
return;
}
for(i = 0; i< size; ++i)
{
printf("%s", strArr[i]);
}
}
int main(void)
{
char * arr[3]; /*array of (char*) each will point to a string after sending it to the function */
read_strings(arr,3);
printStringsArray(arr,3);
return 0;
}
Related
Any hints on how I would dynamically allocate myArray so I can enter any amount of strings and it would store correctly.
int main()
{
char myArray[1][1]; //how to dynamically allocate the memory?
counter = 0;
char *readLine;
char *word;
char *rest;
printf("\n enter: ");
ssize_t buffSize = 0;
getline(&readLine, &buffSize, stdin);//get user input
//tokenize the strings
while(word = strtok_r(readLine, " \n", &rest )) {
strcpy(myArray[counter], word);
counter++;
readLine= rest;
}
//print the elements user has entered
int i =0;
for(i = 0;i<counter;i++){
printf("%s ",myArray[i]);
}
printf("\n");
}
Use realloc like this:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int main(void){
char **myArray = NULL;
char *readLine = NULL;
size_t buffSize = 0;
size_t counter = 0;
char *word, *rest, *p;
printf("\n enter: ");
getline(&readLine, &buffSize, stdin);
p = readLine;
while(word = strtok_r(p, " \n", &rest )) {
myArray = realloc(myArray, (counter + 1) * sizeof(*myArray));//check omitted
myArray[counter++] = strdup(word);
p = NULL;
}
free(readLine);
for(int i = 0; i < counter; i++){
printf("<%s> ", myArray[i]);
free(myArray[i]);
}
printf("\n");
free(myArray);
}
Here is one way you might approach this problem. If you are going to dynamically allocate storage for an unknown number of words of unknown length, you can start with a buffSize that seems reasonable, allocate that much space for the readLine buffer, and grow this memory as needed. Similarly, you can choose a reasonable size for the number of words expected, and grow word storage as needed.
In the program below, myArray is a pointer to pointer to char. arrSize is initialized so that pointers to 100 words may be stored in myArray. First, readLine is filled with an input line. If more space than provided by the initial allocation is required, the memory is realloced to be twice as large. After reading in the line, the memory is again realloced to trim it to the size of the line (including space for the '\0').
strtok_r() breaks the line into tokens. The pointer store is used to hold the address of the memory allocated to hold the word, and then word is copied into this memory using strcpy(). If more space is needed to store words, the memory pointed to by myArray is realloced and doubled in size. After all words have been stored, myArray is realloced a final time to trim it to its minimum size.
When doing this much allocation, it is nice to write functions which allocate memory and check for errors, so that you don't have to do this manually every allocation. xmalloc() takes a size_t argument and an error message string. If an allocation error occurs, the message is printed to stderr and the program exits. Otherwise, a pointer to the allocated memory is returned. Similarly, xrealloc() takes a pointer to the memory to be reallocated, a size_t argument, and an error message string. Note here that realloc() can return a NULL pointer if there is an allocation error, so you need to assign the return value to a temporary pointer to avoid a memory leak. Moving realloc() into a separate function helps protect you from this issue. If you assigned the return value of realloc() directly to readLine, for example, and if there were an allocation error, readLine would no longer point to the previously allocated memory, which would be lost. This function prints the error message and exits if there is an error.
Also, you need to free all of these memory allocations, so this is done before the program exits.
This method is more efficient than reallocing memory for every added character in the line, and for every added pointer to a word in myArray. With generous starting values for buffSize and arrSize, you may only need the initial allocations, which are then trimmed to final size. Of course, there are still the individual allocations for each of the individual words. You could also use strdup() for this part, but you would still need to remember to free those allocations as well.Still, not nearly as many allocations will be needed as when readLine and myArray are grown one char or one pointer at a time.
#define _POSIX_C_SOURCE 1
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
void * xmalloc(size_t size, char *msg);
void * xrealloc(void *ptr, size_t size, char *msg);
int main(void)
{
char **myArray;
size_t buffSize = 1000;
size_t arrSize = 100;
size_t charIndex = 0;
size_t wordIndex = 0;
char *readLine;
char *inLine;
char *word;
char *rest;
char *store;
/* Initial allocations */
readLine = xmalloc(buffSize, "Allocation error: readLine");
myArray = xmalloc(sizeof(*myArray) * arrSize,
"Allocation error: myArray\n");
/* Get user input */
printf("\n enter a line of input:\n");
int c;
while ((c = getchar()) != '\n' && c != EOF) {
if (charIndex + 1 >= buffSize) { // keep room for '\0'
buffSize *= 2;
readLine = xrealloc(readLine, buffSize,
"Error in readLine realloc()\n");
}
readLine[charIndex++] = c;
}
readLine[charIndex] = '\0'; // add '\0' terminator
/* If you must, trim the allocation now */
readLine = xrealloc(readLine, strlen(readLine) + 1,
"Error in readLine trim\n");
/* Tokenize readLine */
inLine = readLine;
while((word = strtok_r(inLine, " \n", &rest)) != NULL) {
store = xmalloc(strlen(word) + 1, "Error in word allocation\n");
strcpy(store, word);
if (wordIndex >= arrSize) {
arrSize *= 2;
myArray = xrealloc(myArray, sizeof(*myArray) * arrSize,
"Error in myArray realloc()\n");
}
myArray[wordIndex] = store;
wordIndex++;
inLine = NULL;
}
/* You can trim this allocation, too */
myArray = xrealloc(myArray, sizeof(*myArray) * wordIndex,
"Error in myArray trim\n");
/* Print words */
for(size_t i = 0; i < wordIndex; i++){
printf("%s ",myArray[i]);
}
printf("\n");
/* Free allocated memory */
for (size_t i = 0; i < wordIndex; i++) {
free(myArray[i]);
}
free(myArray);
free(readLine);
return 0;
}
void * xmalloc(size_t size, char *msg)
{
void *temp = malloc(size);
if (temp == NULL) {
fprintf(stderr, "%s\n", msg);
exit(EXIT_FAILURE);
}
return temp;
}
void * xrealloc(void *ptr, size_t size, char *msg)
{
void *temp = realloc(ptr, size);
if (temp == NULL) {
fprintf(stderr, "%s\n", msg);
exit(EXIT_FAILURE);
}
return temp;
}
I suggest you first scan the data and then call malloc() with the appropriate size.
Otherwise, you can use realloc() to reallocate memory as you go through the data.
How would I go about copying the characters of a char array into a char pointer without using strcpy aka manually. For example:
char *Strings[NUM];
char temp[LEN];
int i;
for (i = 0; i < NUM; i++){
fgets(temp, LEN, stdin);
Strings[i] = malloc(strlen(temp)+1);
Strings[i] = temp; // What would go here instead of this,
// because this causes this to happen->
}
Input:
Hello
Whats up?
Nothing
Output (when the strings in the array of char pointers are printed):
Nothing
Nothing
Nothing
I'm not sure how to fix this problem.
In your example, you use these two lines:
Strings[i] = malloc(strlen(temp)+1); /* you should check return of malloc() */
Strings[i] = temp;
Which is incorrect. The second line just overwrites the pointer given back from malloc(). You need to instead use strcpy() from <string.h>:
Strings[i] = malloc(strlen(temp)+1);
strcpy(Strings[i], temp);
char *strcpy(char *dest, const char *src) copies the string pointed to, from src to dest. dest is the destination, and src is the string to be copied. Returns a pointer to dest.
You are also not checking the return of fgets(), which returns NULL on failure. You should also consider removing the \n character appended by fgets(), as the strings you copy into Strings[i] will have a trailing newline, which might not be what you want.
Since another answer showed how to do it manually, you might want to also consider just using strdup() to do the copying for you.
strdup() returns a pointer to a new string which is duplicate of string str. Memory is obtained from malloc(), and deallocated from the heap with free().
Here is some example code which does extra error checking.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define LEN 3
#define BUFFSIZE 20
int main(void) {
char *strings[LEN] = {NULL};
char buffer[BUFFSIZE] = {'\0'};
size_t slen, strcnt = 0, i;
printf("Input:\n");
for (i = 0; i < LEN; i++) {
if (fgets(buffer, BUFFSIZE, stdin) == NULL) {
fprintf(stderr, "Error from fgets()\n");
exit(EXIT_FAILURE);
}
slen = strlen(buffer);
if (slen > 0 && buffer[slen-1] == '\n') {
buffer[slen-1] = '\0';
} else {
fprintf(stderr, "Too many characters entered\n");
exit(EXIT_FAILURE);
}
if (*buffer) {
strings[strcnt] = strdup(buffer);
if (strings[strcnt] == NULL) {
fprintf(stderr, "Cannot allocate buffer\n");
exit(EXIT_FAILURE);
}
strcnt++;
}
}
printf("\nOutput:\n");
for (i = 0; i < strcnt; i++) {
printf("%s\n", strings[i]);
free(strings[i]);
strings[i] = NULL;
}
return 0;
}
So what is happening is you change the value of temp but all the pointers point to the one instance of temp. You need to allocate the memory and then copy over the array manually.
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
int main()
{
int LEN = 20;
int NUM = 3;
char* Strings[NUM];
char temp[LEN];
int i,j;
for (i=0;i<NUM;i++){
fgets(temp,LEN,stdin);
Strings[i] = (char*)malloc(strlen(temp)+1);
for(j=0;j<=strlen(temp);j++) { /* this part */
if (j == strlen(temp))
Strings[i][j - 1] = temp[j]; /* overwrite \n with the terminating \0 */
else
Strings[i][j] = temp[j];
}
}
for (i=0;i<NUM;i++)
printf("%s\n", Strings[i]);
return 0;
}
While adding string to my pointer's array, it is being overwriten by the last one. Could anyone tell me, where's my mistake?
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
int main (){
int ile = 3;
const char * slowa[ile];
for(int j = 0; j < ile; j++){
char string[30];
gets(string);
slowa[j] = string;
printf ("%s dodalem pierwsza\n",string);
}
for (int i = 0; i < ile; i++) {
printf ("%s numer %d\n",slowa[i],i);
}
return 0;
}
The answer is in the following two lines of code:
char string[30];
...
slowa[j] = string;
The assignment sets slowa[j] to the address of the same buffer, without making a copy. Hence, the last thing that you put in the buffer would be referenced by all elements of slowa[] array, up to position of j-1.
In order to fix this problem, make copies before storing values in slowa. You can use non-standard strdup, or use malloc+strcpy:
char string[30];
gets(string);
slowa[j] = malloc(strlen(string)+1);
strcpy(slowa[j], string);
In both cases you need to call free on all elements of slowa[] array to which you have assigned values in order to avoid memory leaks.
You're always pointing to array of chars which is stack variable it's locally allocated only in scope of function, possibly each declaration of string will be on the same address as previous iteration in your loop. You could either instead of using array of chars allocate memory each loop iteration or use array and then using i.e strdup allocate memory for your new string like
slowa[j] = strdup(string) :
As others have said, you need to create copies of the strings, otherwise you set the strings to the same address, and therefore they just overwrite each other.
Additionally, I think using fgets over gets is a much safer approach. This is because gets is very prone to buffer overflow, whereas with fgets, you can easily check for buffer overflow.
This is some code I wrote a while ago which is similar to what you are trying to achieve:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define PTRS 3
#define STRLEN 30
int
string_cmp(const void *a, const void *b) {
const char *str1 = *(const char**)a;
const char *str2 = *(const char**)b;
return strcmp(str1, str2);
}
int
main(void) {
char *strings[PTRS];
char string[STRLEN];
int str;
size_t len, i = 0;
while (i < PTRS) {
printf("Enter a string: ");
if (fgets(string, STRLEN, stdin) == NULL) {
fprintf(stderr, "%s\n", "Error reading string");
exit(EXIT_FAILURE);
}
len = strlen(string);
if (string[len-1] == '\n') {
string[len-1] = '\0';
} else {
break;
}
strings[i] = malloc(strlen(string)+1);
if (strings[i] == NULL) {
fprintf(stderr, "%s\n", "Cannot malloc string");
exit(EXIT_FAILURE);
}
strcpy(strings[i], string);
i++;
}
qsort(strings, i, sizeof(*strings), string_cmp);
printf("\nSuccessfully read strings(in sorted order):\n");
for (str = 0; str < i; str++) {
printf("strings[%d] = %s\n", str, strings[str]);
free(strings[str]);
strings[str] = NULL;
}
return 0;
}
So I'm trying to program a function which allows the user to enter an unlimited amount of chars. For example this:
char string[100]
limits the input to 100 characters.
The code i have so far is:
#include<stdio.h>
char* uinput(){
char *string, *current;
int counter = 0;
string = (char *) malloc(10 * sizeof(char));
do{
realloc(string, counter * sizeof(char));
current = string + counter;
*current = getchar();
counter++;
}while(*current != '\n');
return string;
}
int main(){
char *s;
s = uinput();
printf("\nYou entered: %s", *s);
return 0;
}
I'm new to pointers, so I'm not sure why this doesn't work(Program crashes). What I'm trying to do is keep reading a character and keep relocating the string pointer so the amount of bytes keeps increasing until the user presses enter ('\n').
Thanks
~Raf
Ok I think this is the problem
you are re-allocing
realloc(string, counter * sizeof(char));
The what will be the size of string in first iteration? It will be 0.
Now you are writing to a pointer which has 0 bytes allocated and hence segfault.
Changing it to a while loop can help to fix it. You can also change the initial value of counter to fix it
The approach is sane, but there are minor details that are wrong. If you compile with warnings enabled, you'd notice that you're missing <stdlib.h>; also you're giving the first character to printf instead of the pointer to the buffer.
Then there is the obvious bug that your size is reset to 0, and you're casting the return value of malloc, using char to store the result of getchar() which is also wrong because you cannot check against EOF. You're not saving the realloced pointer; and you're not terminating the string properly. On minor detail, you'd want to double the size of buffer in each realloc, because realloc needs to potentially copy the whole line, so it becomes slower and slower over time as the line grows in length.
Thus we get:
#include <stdio.h>
#include <stdlib.h>
char* uinput() {
char *string;
// number of characters in the buffer
size_t counter = 0;
// size of allocated buffer
size_t allocated = 16;
int c;
string = malloc(allocated); // sizeof(char) is 1
do {
c = getchar();
if (c == EOF) {
break;
}
// if our buffer is too small, double the allocation
if (counter + 2 <= allocated) {
size_t new_size = allocated * 2;
char *new_buffer = realloc(string, new_size);
if (! new_buffer) {
// out of memory? try smaller increment
new_size = allocated + 16;
new_buffer = realloc(string, new_size);
if (! new_buffer) {
// really out of memory: free old block
free(string);
return NULL;
}
}
allocated = new_size;
string = new_buffer;
}
// store the character
string[counter++] = c;
} while (c != '\n');
// terminate the buffer properly
string[counter - 1] = '\0';
return string;
}
int main() {
char *s = uinput();
if (!s) {
// possibly out of memory in uinput
perror("Error reading input");
exit(EXIT_FAILURE);
}
printf("\nYou entered: %s", s);
free(s);
return EXIT_SUCCESS;
}
You could try something like the following:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
struct person{
char *name;
}pers;
void addMem(void);
int main(void){
addMem();
printf("\nYour name is:> %s\n",pers.name);
free(pers.name);
pers.name = NULL;
return 0;
}
void addMem(void){
unsigned int length = 6;
size_t newLength = 0;
unsigned int newSize = 0;
unsigned int i =0;
char *name;
int c;
name = malloc(length);
if(name == NULL){
exit(1);
}
newSize = length;
printf("Enter your name:> ");
while ((c = getchar()) != '\n' && c!=EOF){
name[i++]=(char)c;
if(i == newSize){
newSize = i+length;
name = realloc(name, newSize);
}
}
name[i] = '\0';
newLength = strlen(name)+1;
pers.name = malloc(newLength);
memcpy(pers.name, name, newLength);
free(name);
name = NULL;
}
Another approach is to use fgets(), which gets a string into a sized buffer from the input stream; if it has the complete input then the string ends with \n; if it doesn't then it doesn't. So you can loop calling fgets until there is an EOL character at the end, then depending on what your program does with the input you can decide whether to keep realloc-ing or to process the input a bit at a time.
use getchar, malloc and realloc for reading the unlimited input string
Declare String type, you can also use char *
// String type
typedef char *String;
I write this function for joining the char in the end of string
/**
* Join the Char into end of String
*
* #param string - String
* #param c - joined char
*/
void String_joinChar(String *string, const char c)
{
const size_t length = strlen(*string);
(*string) = (String)realloc((*string), sizeof(char) * (length + 2));
(*string)[length] = c;
(*string)[length + 1] = '\0';
}
This function for inputting string, which read the char from keyboard by using getchar and join it in the end of current string.
/**
* Input String
*
* #return Inputed String
*/
String String_input()
{
String string = (String)malloc(sizeof(char));
strcpy(string, "");
char cursor;
fflush(stdin);
while ((cursor = getchar()) != '\n' && cursor != EOF)
{
String_joinChar(&string, cursor);
}
return string;
}
Cause of using char *, malloc and realloc, we must free it
/**
* Destroy String
*
* #param string - Destroyed String
*/
void String_destroy(String string)
{
free(string);
}
And now we just use it !!
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int main()
{
String string = String_input();
printf("\n%s\n", string);
String_destroy(string);
return 0;
}
Hope useful to you!
I'm working on a program for a C class and I reached a point where I don't know what to do. We are implementing a String library type.
I have my header file (MyString.h)
typedef struct {
char *buffer;
int length;
int maxLength;
} String;
String *newString(const char *str);
The file implementing the functions (MyString.c)
#include <stdlib.h>
#include <stdio.h>
#include "MyString.h"
String *newString(const char *str) {
// Allocate memory for the String
String *newStr = (String*)malloc(sizeof(String));
if (newStr == NULL) {
printf("ERROR: Out of memory\n");
return NULL;
}
// Count the number of characters
int count;
for (count = 0; *(str + count) != '\0'; count++);
count++;
// Allocate memory for the buffer
newStr->buffer = (char*)malloc(count * sizeof(char));
if (newStr->buffer == NULL) {
printf("ERROR: Out of memory\n");
return NULL;
}
// Copy into the buffer
while (*str != '\0')
*(newStr->buffer++) = *(str++);
*(++newStr->buffer) = '\0';
// Set the length and maximum length
newStr->length = count;
newStr->maxLength = count;
printf("newStr->buffer: %p\n",newStr->buffer); // For testing purposes
return newStr;
}
And a tester (main.c)
#include <stdio.h>
#include "MyString.h"
main() {
char str[] = "Test character array";
String *testString = newString(str);
printf("testString->buffer: %p\n",testString->buffer); // Testing only
}
The problem is that, even though testString is pointing to the String created in newString(), their buffers point to different memory addresses. Why is that?
Thanks in advance
By using *(++newStr->buffer) and *(newStr->buffer++), you're moving newStr->buffer to essentially point to the end of the string.. You need to modify your code as such:
#include <stdlib.h>
#include <stdio.h>
#include "MyString.h"
String *newString(const char *str) {
// Allocate memory for the String
String *newStr = (String*)malloc(sizeof(String));
if (newStr == NULL) {
printf("ERROR: Out of memory\n");
return NULL;
}
// Count the number of characters
int count;
for (count = 0; *(str + count) != '\0'; count++);
count++;
// Allocate memory for the buffer
newStr->buffer = (char*)malloc(count * sizeof(char));
if (newStr->buffer == NULL) {
printf("ERROR: Out of memory\n");
return NULL;
}
char *pBuffer = newStr->buffer; // don't move newStr->buffer, have another pointer for that.
// Copy into the buffer
while (*str != '\0')
*(pBuffer++) = *(str++);
*pBuffer = '\0';
// Set the length and maximum length
newStr->length = count;
newStr->maxLength = count;
printf("newStr->buffer: %p\n", newStr->buffer); // For testing purposes
return newStr;
}
As the other colleagues already pointed out, you modified your allocation pointer, which is a no no. Here your example but translated to a more "professional" way.
I would change your structure to:
typedef struct {
char *buffer;
size_t length; /* strings and allocation in C are of type size_t not int */
size_t alloclength;
} String;
String *newString(const char *str);
And the function would be changed to.
#include <stdlib.h>
#include <stdio.h>
#include "MyString.h"
String *newString(const char *str)
{
// Allocate memory for the String
String *newStr = malloc(sizeof (String)); /* No typecast of void * in C, it's bad taste. */
if(!newStr) {
fprintf(stderr, "ERROR: Out of memory\n"); /* Errors are meant to be printed on stderr, not stdio */
return NULL;
}
// Count the number of characters
newStr->length = strlen(str); /* Learn to use the stdlib, there are a lot of usefull functions */
newStr->alloclength = newStr->length+1;
// Allocate memory for the buffer
newStr->buffer = malloc(newStr->alloclength); /* sizeof (char) is by definition always 1 */
if(!newStr->buffer) {
fprintf(stderr, "ERROR: Out of memory\n");
free(newStr);
return NULL;
}
// Copy into the buffer
strcpy(newStr->buffer, str); /* Because we already scaned the input with strlen, we can use safely the "unsafe" strcpy function. The strcpy will add the trailing 0 */
printf("newStr->buffer: %p\n",newStr->buffer); // For testing purposes
return newStr;
}
You are modifying the buffer pointer inside the newly created String struct.
You should do:
char *newBuffer = newStr->buffer;
// Copy into the buffer
while (*str != '\0')
*(newBuffer++) = *(str++);
*(++newBuffer) = '\0';
The question is answered, but I think that there is a piece of code that you should add to avoid a subtle source of memory leak:
// Allocate memory for the buffer
newStr->buffer = (char*)malloc(count * sizeof(char));
if (newStr->buffer == NULL) {
printf("ERROR: Out of memory\n");
free(newStr); // free the memory allocated for newStr
return NULL;
}
The explanation is pretty simple: You are modifying the buffer pointer in the newString() function:
// Copy into the buffer
while (*str != '\0')
*(newStr->buffer++) = *(str++);
*(++newStr->buffer) = '\0';
You could use a temporary pointer here (like suggested in the other answers), but I'd like to recommend using the standard functions provided within string.h:
// Count the number of characters
int count;
count = strlen(str) + 1;
// Copy into the buffer
memcpy(newString->buffer, str, count)