How to declare a dynamic array of char in c - c

I'm trying to declare an array of char dynamically, what I need to do is adding the newest character to the string which works fine, the problem is that when I try to print it out, at the beginning of the string there are some unknown characters.
char add[2];
char str2[200];
char c;
int temp = -1;
int num = 0;
char *str3;
str3 = malloc( (size_t)count ); //str3 = malloc(sizeof(char)) not working
while((c= getch()) !='\r')
{
for (int i = 0;i<200;i++)
{
if (str2[i] =='\0')
{
num = i;
break;
}
}
//printf("Num: %d\n",num);
if ((temp == -32) || (temp == 0))
{
}
else
{
if(isalnum((char)c) == 0)
{
if((c == '\'') || (c == -118) || (c == -115) || (c == -107) || (c == -123) || (c == -105)|| (c == 32))
{
realloc(str3,sizeof(char)+2);
printf("true: %c\n",c);
//realloc(str2,sizeof(char)+1);
add[1] = '\0';
add[0] = c;
strcat(str3,add);
strcat(str2,add);
printf("%s\n",str2);
printf("%s\n",str3);
}
else if (c == 8)
{
printf("Deleting something...\n");
}
}
else
{
realloc(str3,sizeof(char)+2);
printf("true: %c\n",c);
//realloc(str2,sizeof(char)+1);
add[1] = '\0';
add[0] = c;
strcat(str3,add);
strcat(str2,add);
printf("%s\n",str2);
printf("%s\n",str3);
}
}
printf("ASCII Code: %d\n",c);
temp = c;
}

To get some memory to your string, you have to tell malloc how many bytes of memory you want. sizeof(char) returns 1, therefore, you'll only have 1 byte. In C, strings are terminated by the NULL byte (\0), and printf and others will print until they find that NULL terminator.
If you do something like this:
char *str = malloc(1);
*str = 'a';
printf("%s", str);
You will probably get a very strange output, since you have no NULL terminator.
When you use the unsigned x; str = malloc(x);, it's actually undefined how many bytes you have, since that x variable is not initialized.
Since your question is very unclear, what I can tell you (from what I think you're asking) is how to actually get space for a string of 63 characters plus the NULL terminating byte.
char *str = malloc(64);
strcpy(str, "Stack Overflow");
printf("%s", str);
That will do it.
Also note that the memory block returned by malloc will not be zeroed, therefore you can't possibly know what's in it (that could be the reason you're getting garbage when you're printing).
I recommend you read about memory allocation in a good C book or in Wikipedia...
After your edit and "MCVE"
I made some edits to what I think it is you want. The modifications are explained in the comments of the source. Let me know if you have any doubts.
#include <stdio.h> /* printf */
#include <stdlib.h> /* malloc, free, realloc */
#include <string.h> /* strcat */
#include <ctype.h> /* isalnum */
#include <conio.h> /* getch */
int main(void)
{
char add[2];
char str2[200];
char c;
int temp = -1;
int num = 0;
char *str3;
/* I just think 'count' is an int, since you didn't put it in the code,
* I also deduced that #count will be used as the length of #str3
*/
int count;
/* Here, count is not initialized, so you MUST initialize it in order
* to call malloc with it! Since it seems you want to add character by
* character using realloc, then we just malloc() 2 bytes - 1 for a
* character and one for the NULL terminator.
*/
count = 2;
str3 = malloc(count);
/* You will be using #strcat to append strings to #str3, so you need
* to put a NULL terminator in it, because strcat will look for that
* NULL byte to find where it should append
*/
*str3 = 0x0;
while((c = getch()) != '\r') {
for (int i = 0;i < 200; i++) {
if (str2[i] =='\0') {
num = i;
break;
}
}
if ((temp == -32) || (temp == 0)) {
/* empty */
} else {
if(isalnum((char)c) == 0)
{
if((c == '\'') || (c == -118) || (c == -115) || (c == -107) || (c == -123) || (c == -105)|| (c == 32))
{
/* this is not the optimal way of using realloc, because
* you should first check for errors, but will do for
* this example.
* You must assign the returned value of realloc to str3.
*
* Also, since #count contains the length
* of #str3, you need to increment it.
*/
str3 = realloc(str3, ++count);
printf("true: %c\n",c);
add[1] = '\0';
add[0] = c;
strcat(str3,add);
strcat(str2,add);
printf("str2: %s\n",str2);
printf("str3: %s\n",str3);
} else if (c == 8) {
printf("Deleting something...\n");
}
} else {
/* see notes above on realloc */
str3 = realloc(str3, ++count);
printf("true: %c\n",c);
add[1] = '\0';
add[0] = c;
strcat(str3,add);
strcat(str2,add);
printf("str2: %s\n",str2);
printf("str3: %s\n",str3);
}
}
printf("ASCII Code: %d\n",c);
temp = c;
}
return 0;
}

In the first two cases, you are only allocating enough space for a single char. If you attempt to write more than one to that block of memory, you'll write past the end of the memory that was allocated for you. Doing so invokes undefined behavior, which in this case manifests as printing strange characters.
In the third case, you allocate x bytes of memory, however x is uninitialized and has an indeterminate value. Reading an indeterminate value is also undefined behavior. In this case it happens to work because the indeterminate value happens to be a valid value and is large enough to hold the string you want, however you can't depend on that behavior.
You need to allocate a byte for every character that you'll need, plus 1 for the terminating null byte that ends a string in C.

Note that the first allocation, this one
str = malloc(sizeof(char));
is exactly equivalent to1
str = malloc(1);
so you don't have room except for one character which is a problem, because it only represents an empty string.
If you allocate this much space you will very likely access memory out of the allocated space, causing undefined and unpredictable behavior. You need to understand what a string in c is,
A string in c is a sequence of non-null characters followed by a null character, so for a string with N characters you need N + 1 array elements (for ascii this equals bytes)
According to that definition of string if you wanted to store the string "Hello" you would need at least the following code
char *str = malloc(6);
if (str != NULL) {
str[0] = 'H';
str[1] = 'e';
str[2] = 'l';
str[3] = 'l';
str[4] = 'o';
str[5] = '\0'; // Or equivalently str[5] = 0;
}
as you can see, the last character being '\0' or 0 — which is the same — is very important.
All the functions in the standard library of c which expect a string parameter expect that there is the null terminator. For instance strlen() will count characters until it reaches the '\0', if it's not there then you can't predict where it is going to stop counting, this causing undefined behavior.
1sizeof(char) is as defined by the c standard always equal to one.

Related

Free() doesn't work as expected after calling malloc()

I wrote the following function in C but have 2 problems:
I am asked to free the dynamically allocated memory to prevent using too much RAM but the line free(word) just causes bugs to my program.
if I delete it everything works fine, why is that happening? I used free after I finished using word as suggested in many different articles.
I am requested to use malloc with the minimum needed space but how could I do that?
currently my code allocates max_str_len blocks of RAM but if the word was much shorter like a letter I don't want to allocate 200 blocks for that.
Any suggestions please?
int read_words(char *words[], int size, int max_str_len) {
char *word;
char ch;
int i;
for (i = 0; i < size; ++i) {
word = (char *)malloc((max_str_len + 1) * sizeof(char));
if (word == NULL)
return -1;
for (int j = 0; j < max_str_len; ++j) {
scanf("%c", &ch);
if (ch == '\n') break;
if (ch == EOF || ch == 'R') return i;
word[j] = ch;
}
words[i] = word;
free(word);
}
return i;
}
You put a malloc'd char* into a caller-provided words[i] and then you free it. That doesn't make sense. If you free it, the caller can't do anything with it.
If you want the malloc'd strings to be minimal you could realloc them or you could read into a large buffer (allocated perhaps at the start of the function) and then copy the result into a malloc'd buffer that's sized just right.
Note that you're also failing to check scanf for errors and that you're leaking memory if you get a memory failure in the middle of the function—by returning -1, you effectively lose info on how many elements of words have been filled with owning pointers. You might want to return that info (return i;) or to free all pointers allocated by the function before the malloc failure.
There are multiple problems in your code:
you free the memory allocated for each word, yet you return pointers to the freed blocks in the array supplied by the caller, causing undefined behavior when the caller will dereference these pointers.
your test for end of file is incorrect: scanf() will return EOF then, bu the character will not be set to EOF, which might not be appropriate for a char anyway. You should use getchar() and make ch an int.
you should set a null terminator at the end of the string read.
you could use realloc to shrink the block of memory once you know the string length.
Here is a modified version:
int read_words(char *words[], int size, int max_str_len) {
char *word, *p;
int i, j, ch;
for (i = 0; i < size;) {
word = (char *)malloc(max_str_len + 1);
if (word == NULL) {
/* free the words allocated so far and return a failure code */
while (i-- > 0)
free(words[i];
return -1;
}
for (j = 0; j < max_str_len; ++j) {
ch = getchar();
if (ch == '\n' || ch == EOF || ch == 'R') break;
word[j] = ch;
}
if (j == 0 && (ch == EOF || ch == 'R'))
break;
word[j] = '\0';
p = (char *)realloc(word, j + 1);
if (p != NULL)
word = p;
words[i++] = word;
if (ch == EOF || ch == 'R')
break;
}
return i;
}

Reading Multiple lines until EOF

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
//the function
char* scan(char *string)
{
int c; //as getchar() returns `int`
string = malloc(sizeof(char)); //allocating memory
string[0]='\0';
for(int i=0; i<100 && (c=getchar())!='\n' && c != EOF ; i++)
{
string = realloc(string, (i+2)*sizeof(char)); //reallocating memory
string[i] = (char) c; //type casting `int` to `char`
string[i+1] = '\0'; //inserting null character at the end
}
return string;
}
char** bigScan(char **string)
{
int c;
string=malloc(sizeof(char *));
string[0]='\0';
for(int i=0;(c=getchar()!=EOF);i++)
{
*string = realloc(string, (i+2)*sizeof(char *)); //reallocating memory
string[i] = scan(string[i]); //type casting `int` to `char`
string[i+1] = '\0'; //inserting null character at the end
}
return string;
}
int main(void)
{
char **buf; //pointer to hold base address of string
buf=bigScan(buf);
printf("%s\n",buf[0] );
}
So basically the scan function reads each line until either EOF or new line.The job of bigScan is to read multiple lines (pointer to strings) by invoking the scan function until we hit EOF. So essentially the big scan returns pointer to pointers and we can read the entire text using this.
What am I doing wrong in my approach ?
Basically invoking the scan function in my bigScan until I Hit EOF.
Ideal Input:
"Hi guys and girls
This is a message in multiple lines."
Ideal Output:
"Hi guys and girls
This is a message in multiple lines."
The (c=getchar()!=EOF) inside bigScan is invalid. It assigns the value of 1 or 0 to c, as the bool value is the result of != comparison.
The getchar() inside bigScan will make you loose one character per line, as that character is nowhere saved.
The allocation in bigScan is invalid. You shouldn't allocate the memory for string *string = realloc(string, but you should allocate the memory for pointers themselves, ie. string = realloc(string, ... sizeof(char*)).
NULL is the terminating value used for pointers. Don't use '\0' for pointers.
Use size_t to store sizes.
There is little point in passing parameters value if you are overwriting them. In this function the variable a is unused void f(int a) { a = 1; } as the variable string in your both functions are assigned immediately after entering the function.
The function scan has a hard limit of i<100 characters.
Below is somewhat fixed version of your functions. With also renamed variables. And removed parameters. And different indentation. And with assertions from the standard #include <assert.h> to use as a primitive error checking. And with ungetc so the character read in bigScan doesn't disappear. And I haven't run this code, so it has ton of errors.
char* scan(void)
{
char *string = malloc(sizeof(*string));
assert(string != NULL);
string[0] = '\0';
size_t stringlen = 1;
for(int c; (c=getchar()) != '\n' && c != EOF;) {
void * const ptr = realloc(string, (stringlen + 1) * sizeof(*string));
assert(ptr != NULL);
stringlen++;
string[stringlen - 2] = c;
string[stringlen - 1] = '\0'; //inserting null character at the end
}
return string;
}
char** bigScan(void)
{
char **strings = malloc(sizeof(*strings));
assert(strings != NULL);
strings[0] = NULL;
size_t stringslen = 1;
for(int c; (c = getchar()) != EOF;) {
ungetc(c);
void * const ptr = realloc(strings, (stringslen + 1) * sizeof(*strings));
assert(ptr != NULL);
strings = ptr;
stringslen++;
strings[stringslen - 2] = scan();
strings[stringslen - 1] = NULL;
}
return strings;
}

C program strings

For part of my program I would like to concatenate two strings together with an asterisk between each character. For example, if I had a first string of "abcde" and a second string of "1234567", I would like to have a result of "a*b*c*d*e*1*2*3*4*5*6*7*".
For this part of the program I have:
char *widen_stars(char *one, char *two)
{
int length_one = strlength(one); // length of first parameter
int length_two = strlength(two); // Length of second parameter
char *p = malloc((sizeof(char) * (length_one + length_two) * 2)+ 1), *p_start; //Allocate enough memory for both strings concatenated together with a * between each letter
p_start = p;
while(*one != '0')
{
if( (p - p_start) % 2 == 0) // Keeps track of where we are in the p string
{
*p = *one;
p++;
one++;
}
else
{
*p = '*';
p++;
}
}
while(*two != '0')
{
if( (p - p_start) % 2 == 0)
{
*p = *two;
p++;
two++;
}
else
{
*p = '*';
p++;
}
}
return p_start;
}
int main(int argc, char *argv[])
{
char first[31]= {0};
char second[31]= {0};
char *f = first, *s = second;
printf("Please enter a string of maximum 30 characters: ");
scanf("%s", f);
printf("Please enter a string of maximum 30 characters: ");
scanf("%s", s);
printf("The combined string is: %s\n", widen_stars(f, s));
}
return 0;
}
However, when I run the program with the above inputs, I get something like "a*b*c*d*e*", without any of the second string. If I block out the first while loop into comments to test the second loop, I get something like "1*2*3*4*5*5*7*", which leaves me scratching my head.
Your problem lies here:
while(*oneOrTwo != '0')
If you're looking for the end of the strings, it's '\0' that you should be looking for, not '0'. The former is the end-of-string marker, the latter is simply the character 0.
And, as an aside, there are much less ..., err, verbose ways to do this (assuming it's not class work - if it is, you should go with your current method). For example:
#include <stdio.h>
#include <string.h>
char *widen_stars(char *one, char *two) {
// Need to cater for memory exhaustion.
char *p = malloc((strlen(one) + strlen(two)) * 2) + 1);
if (p == NULL) return NULL;
// Init to empty string in case both inputs empty.
*p = '\0';
// Save string start for return.
char *p_start = p;
// Add character and asterisk for every character in both strings.
while (*one != '\0') {
sprintf(p, "%c*", *one++);
p += 2;
}
while (*two != '\0') {
sprintf(p, "%c*", *two++);
p += 2;
}
// Remove last asterisk (if needed).
// *(--p) = '\0';
// Return result.
return p_start;
}
That's based on your actual expected results, which place an asterisk after each character. However, your specifications call for an asterisk between each character. If you decide to got for the latter, it's a simple matter of un-commenting the penultimate statement in the function, to basically back up and replace the final asterisk with an end-of-string marker.
The problem in your code is in while conditions, you should increment pointers until '\0' not '0'. So instead of doing:
while(*one != '0')
...
while(*two != '0')
You do it like this:
while(*one != '\0')
...
while(*two != '\0')
And as you are returning a dynamically allocated memory, consider using a pointer to this memory, which you free after usage:
char *str = widen_stars(f, s);
printf("The combined string is: %s\n", str);
free(str);

Invalid Next Size (fast) when I try to free a string

when I cannot figure out the issue with my code. The goal of the program is to read words from a text file and add them to a linked list. When I run this:
static char *make_string(char buffer[], int length) {
char *str = (char *)(malloc(length+1));
memcpy(str, buffer, length);
str[length + 1] = '\0';
return str;
}
char *words_next_word() {
char buf[MAXBUF] = {0};
int character = getchar();
int index = 0;
static int count = 0;
printf("it is the %d word \n", count);
count++;
while(isalnum(character) == 0){
character = getchar();
}
while(character != EOF && isalnum(character) != 0){
buf[index] = character;
index++;
character = getchar();
}
return make_string(buf, index);
}
After getting the word from the text file, I add it to a linked list. After adding the word, I free the string. The first 138 words are read and freed without issue. For some reason, the program crashes when trying to read the 138'th word, but I don't know why.
The first 138 words are read and freed without issue.
Not really. The problem exists even in the first make_string() call.
Code is attempting to duplicate the string yet has a off-by-one error.
static char *make_string(char buffer[], int length) {
char *str = (char *)(malloc(length+1)); // size good
memcpy(str, buffer, length); // copy OK
str[length + 1] = '\0'; // null character assigned in wrong place, 1 too far out
return str;
}
Assigning data in the wrong place (assigning out of bounds #EOF) and not defining the value of str[length] with a null character (and later using it) results in undefined behavior.
Here is a strdup() function, yet I suggest trying to code repair your make_string() before reviewing.
The below code does not limit writing to buf[]
while(character != EOF && isalnum(character) != 0){
if (index + 1 >= MAXBUF) {
puts("Too long");
return NULL; // or some other error handling
}
buf[index] = character;

How to dynamically allocate memory space for a string and get that string from user?

I want to read input from user using C program. I don't want to use array like,
char names[50];
because if the user gives string of length 10, then the remaining spaces are wasted.
If I use character pointer like,
char *names;
then I need to allocate memory for that in such a way of,
names = (char *)malloc(20 * sizeof(char));
In this case also, there is a possibility of memory wastage.
So, what I need is to dynamically allocate memory for a string which is of exactly same as the length of the string.
Lets assume,
If the user input is "stackoverflow", then the memory allocated should be of 14 (i.e. Length of the string = 13 and 1 additional space for '\0').
How could I achieve this?
Read one character at a time (using getc(stdin)) and grow the string (realloc) as you go.
Here's a function I wrote some time ago. Note it's intended only for text input.
char *getln()
{
char *line = NULL, *tmp = NULL;
size_t size = 0, index = 0;
int ch = EOF;
while (ch) {
ch = getc(stdin);
/* Check if we need to stop. */
if (ch == EOF || ch == '\n')
ch = 0;
/* Check if we need to expand. */
if (size <= index) {
size += CHUNK;
tmp = realloc(line, size);
if (!tmp) {
free(line);
line = NULL;
break;
}
line = tmp;
}
/* Actually store the thing. */
line[index++] = ch;
}
return line;
}
You could have an array that starts out with 10 elements. Read input character by character. If it goes over, realloc another 5 more. Not the best, but then you can free the other space later.
You can also use a regular expression, for instance the following piece of code:
char *names
scanf("%m[^\n]", &names)
will get the whole line from stdin, allocating dynamically the amount of space that it takes. After that, of course, you have to free names.
If you ought to spare memory, read char by char and realloc each time. Performance will die, but you'll spare this 10 bytes.
Another good tradeoff is to read in a function (using a local variable) then copying. So the big buffer will be function scoped.
Below is the code for creating dynamic string :
void main()
{
char *str, c;
int i = 0, j = 1;
str = (char*)malloc(sizeof(char));
printf("Enter String : ");
while (c != '\n') {
// read the input from keyboard standard input
c = getc(stdin);
// re-allocate (resize) memory for character read to be stored
str = (char*)realloc(str, j * sizeof(char));
// store read character by making pointer point to c
str[i] = c;
i++;
j++;
}
str[i] = '\0'; // at the end append null character to mark end of string
printf("\nThe entered string is : %s", str);
free(str); // important step the pointer declared must be made free
}
First, define a new function to read the input (according to the structure of your input) and store the string, which means the memory in stack used. Set the length of string to be enough for your input.
Second, use strlen to measure the exact used length of string stored before, and malloc to allocate memory in heap, whose length is defined by strlen. The code is shown below.
int strLength = strlen(strInStack);
if (strLength == 0) {
printf("\"strInStack\" is empty.\n");
}
else {
char *strInHeap = (char *)malloc((strLength+1) * sizeof(char));
strcpy(strInHeap, strInStack);
}
return strInHeap;
Finally, copy the value of strInStack to strInHeap using strcpy, and return the pointer to strInHeap. The strInStack will be freed automatically because it only exits in this sub-function.
This is a function snippet I wrote to scan the user input for a string and then store that string on an array of the same size as the user input. Note that I initialize j to the value of 2 to be able to store the '\0' character.
char* dynamicstring() {
char *str = NULL;
int i = 0, j = 2, c;
str = (char*)malloc(sizeof(char));
//error checking
if (str == NULL) {
printf("Error allocating memory\n");
exit(EXIT_FAILURE);
}
while((c = getc(stdin)) && c != '\n')
{
str[i] = c;
str = realloc(str,j*sizeof(char));
//error checking
if (str == NULL) {
printf("Error allocating memory\n");
free(str);
exit(EXIT_FAILURE);
}
i++;
j++;
}
str[i] = '\0';
return str;
}
In main(), you can declare another char* variable to store the return value of dynamicstring() and then free that char* variable when you're done using it.
Here's a snippet which I wrote which performs the same functionality.
This code is similar to the one written by Kunal Wadhwa.
char *dynamicCharString()
{
char *str, c;
int i = 0;
str = (char*)malloc(1*sizeof(char));
while(c = getc(stdin),c!='\n')
{
str[i] = c;
i++;
realloc(str,i*sizeof(char));
}
str[i] = '\0';
return str;
}
char* load_string()
{
char* string = (char*) malloc(sizeof(char));
*string = '\0';
int key;
int sizer = 2;
char sup[2] = {'\0'};
while( (key = getc(stdin)) != '\n')
{
string = realloc(string,sizer * sizeof(char));
sup[0] = (char) key;
strcat(string,sup);
sizer++
}
return string;
}
int main()
{
char* str;
str = load_string();
return 0;
}
realloc is a pretty expensive action...
here's my way of receiving a string, the realloc ratio is not 1:1 :
char* getAString()
{
//define two indexes, one for logical size, other for physical
int logSize = 0, phySize = 1;
char *res, c;
res = (char *)malloc(sizeof(char));
//get a char from user, first time outside the loop
c = getchar();
//define the condition to stop receiving data
while(c != '\n')
{
if(logSize == phySize)
{
phySize *= 2;
res = (char *)realloc(res, sizeof(char) * phySize);
}
res[logSize++] = c;
c = getchar();
}
//here we diminish string to actual logical size, plus one for \0
res = (char *)realloc(res, sizeof(char *) * (logSize + 1));
res[logSize] = '\0';
return res;
}

Resources