I have written a program to take input and dynamically allocate memory using realloc(), however there seems to be an error because if I print the final string char by char I seem to have 2 empty bytes at the end, I am sure this is going to be something silly but I have spent some time trying to discover the cause and have failed so hope to learn something here.
#include <stdio.h>
#include <stdlib.h>
int main(void) {
int count = 0;
char *str;
char tmp;
str = malloc(sizeof(char));
while (tmp != '\n') {
tmp = getchar();
str = realloc(str, (count + 1) * sizeof(char));
*(str + count) = tmp;
count += 1;
}
*(str + count) = '\0';
puts(str);
// This is just to try and see what was happening
for (int i = 0; i <= count; i++)
printf("str[%d] = %c\n", i, str[i]);
free(str);
str = NULL;
return EXIT_SUCCESS;
}
Four things to mention here.
while(tmp != '\n') is reading uninitialised automatic local variable value without initialization. It invokes undefined behaviour.
str = realloc(str, (count + 0x01) * sizeof(char)); is very bad, if realloc() fails, you'll lose the actual pointer, too. Always use a temporary pointer to hold the return value from realloc() and after proper error check, assign it back to the main pointer.
sizeof(char) is guaranteed to be 1. You don't need to use as a multiplier. It's redundant.
The for loop condition, should be i < count otherwise, you'll run into off-by-one error. C uses 0 based indexing.
That said,
You should always check for the success of the return vale of realloc() and family of functions for success before using the returned pointer.
getchar() returns an int. You should change the type of tmp to int tmp = 0;
This loop should look at least like
for(int i = 0; i < count; i++)
^^^
printf("str[%d] = %c\n", i, str[i]);
Or it would be better to write
for(int i = 0; str[i]; i++)
printf("str[%d] = %c\n", i, str[i]);
Or
int i = 0;
for ( char *p = str; *p; ++p )
printf( "str[%d] = %c\n", i++, *p );
And change these statements
while(tmp != '\n') {
tmp = getchar();
to
while ( ( tmp = getchar() ) != EOF && tmp != '\n' )
Also it would be more safe instead of this statement
str = realloc(str, (count + 0x01) * sizeof(char));
to write
char *p = realloc(str, (count + 0x01) * sizeof(char));
if ( !p ) break;
else str = p;
Apart from the uninitialized variable access, the two “empty characters” are:
a newline, since you check for \n before you read and store the next character, and
a character in uninitialized memory since you’re incorrectly looping while i <= count and not while i < count.
Use a for (;;) (infinite loop) and check if (tmp == '\n') { break; } immediately after getchar() to avoid both the uninitialized variable access and trailing newline.
Related
I have a dynamically sized CHARS array, I'm trying to print the string, using pointers.
I tried something like this:
#include <stdio.h>
#include <ctype.h>
#include <string.h>
#include <stdlib.h>
int main(){
char *str = NULL;
int size = 0;
int c, i;
printf("Please enter your command\n");
while((c = getchar()) != EOF)
{
str = (char *)realloc(str, size + 1);
str[size++] = c;
}
str = (char *)realloc(str, size + 1);
str[size] = '\0';
free(str);
printf("\nThe size is %d\n", size);
/* here I want to print the string */
for(i = *str; i!='\0'; i++){
printf("%c", *str+i);
}
return 0;
}
This code does not print the string. The topic of using pointers is not really clear to me, so I think there is my mistake.
You deallocated early allocated memory
free(str);
So after this statement the pointer str is invalid and accessing memory using the pointer invokes undefined behavior. You need to free the memory when the allocated character array will not be required any more.
This for loop
/* here I want to print the string */
for(i = *str; i!='\0'; i++){
printf("%c", *str+i);
}
does not make sense. In this for loop the variable i that stores the code of the first character of the string stored in the dynamically allocated array is incremented. For example if the first character of the string is 'A' that is in ASCII 65 then after the first iteration it will be equal to 66 that corresponds to the character 'B'. And the expression *str + i will look like 'A' + 'B' that is the same as 65 + 66.
If you are going to outputted the stored string using a pointer then you should write for example
/* here I want to print the string */
for ( const char *p = str; *p != '\0'; ++p ){
printf("%c", *p);
}
putchar( '\n' );
You need to free the memory when you do not need it anymore.
Move free(str) to the end of main.
Also printf("%c", *str+i); is wrong. You need to printf("%c", *(str+i));
You do not check the result of realloc.
char *tmp;
tmp = realloc(str, size + 1);
if(tmp)
{
str = tmp;
str[size++] = c;
}
else
{
/* handle error */
}
+++ more issues so I will post the working code:
int main(void){
char *str = NULL;
size_t size = 0;
int c;
size_t i;
printf("Please enter your command\n");
while((c = getchar()) != EOF)
{
char *tmp;
tmp = realloc(str, size + 2);
if(tmp)
{
str = tmp;
str[size++] = c;
}
else
{
return 1;
}
}
str[size] = '\0';
printf("\nThe size is %zu\n", size);
/* here I want to print the string */
for(i = 0; str[i]; i++){
printf("%c", *(str+i));
}
free(str);
return 0;
}
So I have an double char point guess and I have already malloc space for it and I have realloc for extra characters when enetered to get the right amount of memory allocated. The issue I'm having is that it segfaults whenever it hit *guess[i] = input and I cant figure out why ifI pass it \n from stdin it works and passes through the for loop but whenever there are more than one character from stdin it segfaults
Heres the for loop and malloc prior to it
char input;
guess = (char**) malloc(1*sizeof(char));
for(int i = 0; input != '\n'; i++)
{
input = getc(stdin);
lengthG += 1;
*guess =(char *) realloc(*guess, lengthG * sizeof(char));
*guess[i] = input;
}
And heres the whole function
int fund_check_input(char *val, char **guess)
{
size_t lengthV = 0;
size_t lengthG = 0;
for(int i = 0; val[i] != '\0'; i++)
{
if(lengthV < 4)
{
if(val[i] < 48 || val[i] > 57)
return -1;
else
lengthV += 1;
}
else
return -1;
}
char input;
guess = (char**) malloc(1*sizeof(char));
for(int i = 0; input != '\n'; i++)
{
input = getc(stdin);
lengthG += 1;
*guess =(char *) realloc(*guess, lengthG * sizeof(char));
*guess[i] = input;
}
printf("%s\n", "hey");
if(lengthG != lengthV)
return 0;
else
{
for(int i = 0; *guess[i] != '\0'; i++)
{
if(val[i] != *guess[i])
return 0;
}
}
return 1;
}
I think that I am allocating enough memory because when I increase the amount being realloc'd it still segfaults, so I am not entirely sure what is happening.
Here
guess = (char**) malloc(1*sizeof(char));
^^^^^
you only assign memory for 1 char.
However, it seems you want room for a pointer-to-char.
Did you intend to do:
guess = (char**) malloc(1*sizeof(char*));
^
Also notice
that the type cast is not needed in C.
that guess = malloc(1*sizeof *guess); is in general a better form as you avoid typos like the one you did above. (the 1* can be deleted as well)
That said, consider what the value of *guess is after fixing the above error. You need to make sure it's properly initialized before calling realloc
I'm currently working on making a shell. I want to separate a simple string into a 2D array. At first it was working perfectly, but now I have a strange problem: my simple string "str" changes after I malloc anything. For example, if I create a new array like
char *tmp = malloc(sizeof(char) * 15));
then my str, which was "ls -l", will become something like " OO" or " A".
I've already tried to change the malloc size, but it didn't solve the problem, though it did make str change differently. Her is my code:
char **mem_alloc_2d_array(int nb_rows, int nb_cols) {
char **map = malloc(nb_rows * sizeof(*map + 1));
for (int i = 0; i < nb_rows; i++) {
map[i] = malloc(nb_cols * sizeof(**map + 1));
}
return map;
}
int what_is_x(char const *str) {
int x = 2;
for (int i = 0; str[i] != '\0'; i++) {
if (str[i] == ' ')
x++;
}
return x;
}
char **try_this(char const *str) {
int size = my_strlen(str);
int x = what_is_x(str);
char **words = mem_alloc_2d_array(x, size);
return words;
}
char **my_str_to_wordtab(char *str) {
int j = 0;
int i = 0;
char **words = try_this(str);
if (str[0] == '\n' || str[0] == '\r')
words[0] = NULL;
for (; str[i] == ' ' || str[i] == '\t'; i++);
for (int x = 0; str[i] != '\n'; i++, x++) {
if (str[i] == ' ' || str[i] == '\t') {
words[j][x] = '\0';
j++;
x = 0;
while (str[i] == ' ' || str[i] == '\t')
i++;
}
words[j][x] = str[i];
}
j++;
words[j] = (char *)0;
return words;
}
What I expect is that in the function try_this(), if my str is something big like "ls -l Makefile" then both my_putstr(str) calls will print the same thing, but they don't.
It's unclear what you're talking about with regard to calls to a function my_putstr(str), as neither that function nor any calls to it appear in the code you've presented. Nevertheless, I can say for sure that your memory-allocation code is screwy, and at least partially incorrect. Consider this:
char **map = malloc(nb_rows * sizeof(*map + 1));
. What exactly is the point of the + 1 there? Note that *map has type char *, and therefore so does *map + 1. The sizeof operator computes a result based on the type of its operand, so your sizeof expression computes the same value as sizeof(*map). I'm guessing you probably want
char **map = malloc((nb_rows + 1) * sizeof(*map));
, which reserves space for nb_rows + 1 pointers.
Similarly, this ...
map[i] = malloc(nb_cols * sizeof(**map + 1));
... does not do what you probably intend. To reserve space for a terminator for each string, that would be better written as
map[i] = malloc((nb_cols + 1) * sizeof(**map));
. But since this code is specific to strings, and the size of a char is 1 by definition, I would actually write it like this, myself:
map[i] = malloc(nb_cols + 1);
You not having reserved sufficient space for your data, it is not surprising that you see memory corruption.
Note, too, that checking for memory allocation failure (in which case malloc() returns a null pointer) and handling it appropriately if it occurs are essential for robust code. Do get into the habit of doing that as a matter of routine, although failure to do so is probably not contributing to the particular problem you asked about.
My problem now is that I have taken space for different words,but I'm having problems storing this as an array. Even though there are some similar posts like this, nothing seems to work for me and I'm completely stuck here. I want to keep this format(i don't want to change the definition of the function). Grateful for all help and comments!
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
int i, len = 0, counter = 0;
char ** p = 0;
for(i = 0; s[i] != '\0'; i++){
len++;
if(s[i] == ' ' || s[i+1] == '\0'){
counter ++;
for(i = 0; i < len; i++){
p[i] = s[i];
}
}
printf("%d\n", len);
printf("%d\n", counter);
return p;
}
int main() {
char *s = "This is a string";
int n;
int i;
for(i = 0; i < n*; i++){
//also not sure how to print this
}
}
I edited your code and it's now working correctly:
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
char** split(const char* s, int *n);
char** split(const char* s, int *n) {
int i, len = 0, counter = 0;
char ** p = 0;
for(int i = 0; ; ++i) {
if(s[i] == '\0') {
break;
}
if(s[i] == ' ') {
counter += 1;
}
}
++counter;
p = (char **) malloc(counter * sizeof(char*));
for(int i = 0, c = 0; ; ++i, ++c) {
if(s[i] == '\0') {
break;
}
len = 0;
while(s[len + i + 1] != ' ' && s[len + i + 1] != '\0') {
++len;
}
p[c] = (char *) malloc(len * sizeof(char) + 1);
int k = 0;
for(int j = i; j < i + len + 1; ++j) {
p[c][k++] = s[j];
}
p[c][k] = '\0';
i += len + 1;
}
*n = counter;
return p;
}
int main() {
char *s = "This is a string";
int n;
int i;
char** split_s = split(s, &n);
for(i = 0; i < n; i++) {
printf("%s\n", split_s[i]);
}
}
But I suggest you do a little bit clean-up.
Here is a solution using sscanf. scanf and sscanf considers space as an end of input. I have taken benefit of that to make it work for you.
char *str = (char*) "This is a string";
char buffer[50];
char ** p = (char**)malloc(1 * sizeof(*p));
for (int i = 0; str[0] != NULL; i++)
{
if (i > 0)
{
p = (char**)realloc(p, i * sizeof(p));
}
sscanf(str, "%s", buffer);
int read = strlen(buffer);
str += read + 1;
p[i] = (char*)malloc(sizeof(char)*read + 1);
strcpy(p[i], buffer);
printf("%s\n", p[i]);
}
Since this pointer is growing in both the dimensions, every time a new string is found we need to resize the p itself and then the new address that it contains should be resized too .
My problem now is that I have taken space for different words using malloc, but I'm having problems storing this as an array.
When addressable memory for a collection of strings is needed, then a collection of pointers, as well as memory for each pointer needed.
In your code:
p = (char**)malloc(counter*sizeof(char*));
You have created the collection of pointers, but you have not yet created memory at those locations to accommodate the strings. (By the way, the cast is not necessary)
Here are the essential steps to both create a collection of pointers, and memory for each:
//for illustration, pick sizes for count of strings needed,
//and length of longest string needed.
#define NUM_STRINGS 5
#define STR_LEN 80
char **stringArray = NULL;
stringArray = malloc(NUM_STRINGS*sizeof(char *));// create collection of pointers
if(stringArray)
{
for(int i=0;i<NUM_STRINGS;i++)
{
stringArray[i] = malloc(STR_LEN + 1);//create memory for each string
if(!stringArray[i]) //+1 room for nul terminator
{
//handle error
}
}
}
As a function it could look like this: (replacing malloc with calloc for initialized space)
char ** Create2DStr(size_t numStrings, size_t maxStrLen)
{
int i;
char **a = {0};
a = calloc(numStrings, sizeof(char *));
for(i=0;i<numStrings; i++)
{
a[i] = calloc(maxStrLen + 1, 1);
}
return a;
}
using this in your split() function:
char** split(const char* s, int *n){
int i, len = 0, counter = 0, lenLongest = 0
char ** p = 0;
//code to count words and longest word
p = Create2DStr(counter, longest + 1); //+1 for nul termination
if(p)
{
//your searching code
//...
// when finished, free memory
Let's start at the logic.
How does a string like A quick brown fox. get processed? I would suggest:
Count the number of words, and the amount of memory needed to store the words. (In C, each string ends with a terminating nul byte, \0.)
Allocate enough memory for the pointers and the words.
Copy each word from the source string.
We have a string as an input, and we want an array of strings as output. The simplest option is
char **split_words(const char *source);
where the return value is NULL if an error occurs, or an array of pointers terminated by a NULL pointer otherwise. All of it is dynamically allocated at once, so calling free() on the return value will free both the pointers and their contents.
Let's start implementing the logic according to the bullet points above.
#include <stdlib.h>
char **split_words(const char *source)
{
size_t num_chars = 0;
size_t num_words = 0;
size_t w = 0;
const char *src;
char **word, *data;
/* Sanity check. */
if (!source)
return NULL; /* split_words(NULL) will return NULL. */
/* Count the number of words in source (num_words),
and the number of chars needed to store
a copy of each word (num_chars). */
src = source;
while (1) {
/* Skip any leading whitespace (not just spaces). */
while (*src == '\t' || *src == '\n' || *src == '\v' ||
*src == '\f' || *src == '\r' || *src == ' ')
src++;
/* No more words? */
if (*src == '\0')
break;
/* We have one more word. Account for the pointer itself,
and the string-terminating nul char. */
num_words++;
num_chars++;
/* Count and skip the characters in this word. */
while (*src != '\0' && *src != '\t' && *src != '\n' &&
*src != '\v' && *src != '\f' && *src != '\r' &&
*src != ' ') {
src++;
num_chars++;
}
}
/* If the string has no words in it, return NULL. */
if (num_chars < 1)
return NULL;
/* Allocate memory for both the pointers and the data.
One extra pointer is needed for the array-terminating
NULL pointer. */
word = malloc((num_words + 1) * sizeof (char *) + num_chars);
if (!word)
return NULL; /* Not enough memory. */
/* Since 'word' is the return value, and we use
num_words + 1 pointers in it, the rest of the memory
we allocated we use for the string contents. */
data = (char *)(word + num_words + 1);
/* Now we must repeat the first loop, exactly,
but also copy the data as we do so. */
src = source;
while (1) {
/* Skip any leading whitespace (not just spaces). */
while (*src == '\t' || *src == '\n' || *src == '\v' ||
*src == '\f' || *src == '\r' || *src == ' ')
src++;
/* No more words? */
if (*src == '\0')
break;
/* We have one more word. Assign the pointer. */
word[w] = data;
w++;
/* Count and skip the characters in this word. */
while (*src != '\0' && *src != '\t' && *src != '\n' &&
*src != '\v' && *src != '\f' && *src != '\r' &&
*src != ' ') {
*(data++) = *(src++);
}
/* Terminate this word. */
*(data++) = '\0';
}
/* Terminate the word array. */
word[w] = NULL;
/* All done! */
return word;
}
We can test the above with a small test main():
#include <stdio.h>
int main(int argc, char *argv[])
{
char **all;
size_t i;
all = split_words(" foo Bar. BAZ!\tWoohoo\n More");
if (!all) {
fprintf(stderr, "split_words() failed.\n");
exit(EXIT_FAILURE);
}
for (i = 0; all[i] != NULL; i++)
printf("all[%zu] = \"%s\"\n", i, all[i]);
free(all);
return EXIT_SUCCESS;
}
If we compile and run the above, we get
all[0] = "foo"
all[1] = "Bar."
all[2] = "BAZ!"
all[3] = "Woohoo"
all[4] = "More"
The downside of this approach (of using one malloc() call to allocate memory for both the pointers and the data), is that we cannot easily grow the array; we can really just treat it as one big clump.
A better approach, especially if we intend to add new words dynamically, is to use a structure:
typedef struct {
size_t max_words; /* Number of pointers allocated */
size_t num_words; /* Number of words in array */
char **word; /* Array of pointers */
} wordarray;
Unfortunately, this time we need to allocate each word separately. However, if we use a structure to describe each word in a common allocation buffer, say
typedef struct {
size_t offset;
size_t length;
} wordref;
typedef struct {
size_t max_words;
size_t num_words;
wordref *word;
size_t max_data;
size_t num_data;
char *data;
} wordarray;
#define WORDARRAY_INIT { 0, 0, NULL, 0, 0, NULL }
static inline const char *wordarray_word_ptr(wordarray *wa, size_t i)
{
if (wa && i < wa->num_words)
return wa->data + wa->word[i].offset;
else
return "";
}
static inline size_t wordarray_word_len(wordarray *wa, size_t i)
{
if (wa && i < wa->num_words)
return wa->word[i].length;
else
return 0;
}
The idea is that if you declare
wordarray words = WORDARRAY_INIT;
you can use wordarray_word_ptr(&words, i) to get a pointer to the ith word, or a pointer to an empty string if ith word does not exist yet, and wordarray_word_len(&words, i) to get the length of that word (much faster than calling strlen(wordarray_word_ptr(&words, i))).
The underlying reason why we cannot use char * here, is that realloc()ing the data area (where the word pointers would point to) may change its address. If that were to happen, we'd have to adjust every pointer in our array. It is much easier to use offsets to the data area instead.
The only downside to this approach is that deleting words does not mean a corresponding shrinkage in the data area. However, it is possible to write a simple "compactor" function, that repacks the data to a new area, so that holes left by deleted words are "moved" to the end of the data area. Usually, this is not necessary, but you might wish to add a member to the wordarray structure, say the number of lost characters from word deletions, so that the compaction can be done heuristically the next time the data area would be otherwise resized.
I'm trying to brush up on my C/C++ and I seem to have forgotten how to properly manipulate char arrays.
Code:
#include <iostream>
#include <string.h>
void reverse(char* str)
{
int numChar = strlen(str);
char *reversed = (char*)malloc(sizeof(char) * (numChar + 1));
int i = numChar;
int j = 0;
while(i >= 0)
{
reversed[j] = str[i];
j++;
i--;
printf("%c", reversed[j]);
}
printf("%s", reversed);
}
int main()
{
char* str;
strcpy(str, "apple\0");
reverse(str);
return 0;
}
I'm very certain I'm not doing what I intend to with reversed[j] = str[i] as reversed comes out empty. What's the correct way to go about this?
From first glance, In main(), memory has to be allocated to character pointer str before referencing it in strcpy
int main()
{
char* str = malloc(6) or use char str[6];
// or char *str = "apple"; is sufficient, strcpy is not required in this case
strcpy(str, "apple\0");
reverse(str);
return 0;
}
Another one :
In reverse() function, you will have to increment j after printing
while(i >= 0)
{
reversed[j] = str[i];
printf("%c", reversed[j]);
j++; //Moved here
i--;
}
reversed[j] = '\0' //Null termination
printf("\n %s", reversed);
or only the below two statements would be sufficient enough to post increment j and decrement i
reversed[j] = str[i--];
printf("%c", reversed[j++]);
Since you start with i being the strlen of the input string (e.g. HAHA -> 4), you start copying at haha[4], which is the null byte at the end of the string. IOW you just null terminated your output right at the start. Try setting i to numChar - 1.
(After fixing the problem Santosh A mentioned)
And then, make sure you null terminate the result!