I need to collect some chars into the buffer for my lexer, but I don't know how. I've read some answers on stackoverflow, but those are different cases. I have a while loop that reads next char and I want to put logic in it so it append new char to the buffer in memory.
// init buffer with the first char 'h'
char *buffer = malloc(sizeof(char));
buffer[0] = 'h';
buffer[1] = '\0';
// go through input char by char
while(...)
{
char c = read_next_char();
buffer.append(c) // I whould do in JavaScript, but not in C :(
}
In your case you are allocating a single byte char *buffer = malloc(sizeof(char)); at the beginning and access buffer[1] or any other index is UB.
You can allocate a known number of bytes at beginning and use it until you see a point you need more buffer size.
something like this,
int buffersize = 100;
int index =0;
char *buffer = malloc(sizeof(char)*buffersize); //100bytes are allocated
if(!buffer)
return;
buffer[index++] = 'h';
buffer[index++] = '\0';
// go through input char by char
while(...)
{
char c = read_next_char();
if(index == buffersize ){
buffersize +=100;
buffer= realloc(buffer, buffersize );
//here buffer size is increased by 100
if(!buffer)
return;
}
buffer[index++] = c ;
}
Note: You must free the buffer once the usage is over else it would lead to resource leak.
You need simple to overwrite the null terminating character and add the new one.
char *append(char *buff, int ch)
{
size_t len = strlen(buff);
buff[len] = ch;
buff[len+1] = 0;
return buff;
}
The code assumes that buff is a valid pointer to long enough memory block to accommodate the new char and null terminating char. It has to contain a valid C string.
Unlike in java or javascipt there is no string type in C, you need to write your own.
This is a very simple example of how you could handle the building of strings in an efficient way.
It's pretty self explaining.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
struct DynamicString
{
char* string; // pointer to string
int length; // string length
int capacity; // capacity of the string buffer (= allocated size)
};
#define DS_CHUNKSIZE 100 // we increase the buffer size by DS_CHUNKSIZE
// change this as needed
// Initialize the structure
void InitDynamicString(struct DynamicString* ds)
{
ds->capacity = DS_CHUNKSIZE + 1;
ds->string = malloc(ds->capacity);
ds->string[0] = 0; // null terminator
ds->length = 0; // initial string length 0
};
// Increase the string buffer size if necessary
// (internal function)
void IncreaseSize(struct DynamicString* ds, int newsize)
{
if (ds->length + newsize + 1 > ds->capacity)
{
ds->capacity = ds->length + newsize + DS_CHUNKSIZE + 1;
ds->string = realloc(ds->string, ds->capacity); // reallocate a new larger buffer
}
}
// append a single character
void AppendChar(struct DynamicString* ds, char ch)
{
IncreaseSize(ds, sizeof(char)); // increase size by 1 if necessary
ds->string[ds->length++] = ch; // append char
ds->string[ds->length] = 0; // null terminator
}
// append a string
void AppendString(struct DynamicString* ds, const char *str)
{
IncreaseSize(ds, strlen(str)); // increase by length of string if necessary
strcat(ds->string, str); // concatenate
ds->length += strlen(str); // update string length
}
int main(int argc, char* argv[])
{
struct DynamicString ds;
InitDynamicString(&ds); // initialize ds
AppendChar(&ds, 'a'); // append chars
AppendChar(&ds, 'b');
AppendChar(&ds, 'c');
AppendString(&ds, "DE"); // append strings
AppendString(&ds, "xyz1234");
printf("string = \"%s\"", ds.string); // show result
}
You code could use it like this:
struct DynamicString buffer;
InitDynamicString(&buffer)
dAppendChar(&buffer, 'h');
while(...)
{
char c = read_next_char();
AppendChar(&buffer, c); // quite similar to buffer.append(c)
}
Disclaimer:
The code hasn't been thoroughly tested and there may be bugs.
There is no error checking whatsoever. malloc and realloc may fail.
Other useful functions such as SetString(struct DynamicString *ds, const char *string) need to be written.
There is room for optimisation, especially the strcat could be handled differently, read this article for more information. I leave this as a (very simple) exercise to the reader.
There a no standard function in C that can append a char to a string. You need to write the code from scratch.
Let's start here:
char *buffer = malloc(sizeof(char)); // This allocates memory for ONE char
buffer[0] = 'h'; // So this is fine
buffer[1] = '\0'; // but this is bad. It writes outside the allocated memory
Fix it by allocating memory for two chars
char *buffer = malloc(2); // sizeof(char) is always 1 so no need for it
buffer[0] = 'h';
buffer[1] = '\0';
When you want to append a new character to the string, you also need to allocate memory for it. In other words, you need to increase the size of the memory that buffer is pointing to. For that you can use the function realloc.
size_t buffer_size = 2;
char *buffer = malloc(buffer_size );
buffer[0] = 'h';
buffer[1] = '\0';
while(...)
{
char c = read_next_char();
char* tmp = realloc(buffer, buffer_size + 1);
if (tmp == NULL)
{
// realloc failed ! Add error handling here
... error handling ...
}
buffer = tmp;
buffer[buffer_size - 1] = c; // Add the new char
buffer[buffer_size] = '\0'; // Add the string termination
++buffer_size; // Update buffer size
}
The other answers can work but they are complex. I suggest a simpler solution. A string is an array of char's where the last char of that string is a '\0'-Byte. There can be more char's in the array after it but they are not part of the string.
The simpler solution is to create an array which is large enough for 98% of cases, use it to store the string and when the string gets too long you can exit with an error. Changing the buffer size when needed is a nice feature but when you are new to C you shouldn't start there.
#define BUFFER_SIZE 1024
// init buffer with the first char 'h'
char buffer[BUFFER_SIZE];
buffer[0] = 'h';
buffer[1] = '\0';
// go through input char by char Replace the ... with your condition of the while loop
for(size_t i=1;...;i++) //start at 1 so the 'h' is not overwritten
{
if(i==BUFFER_SIZE-1) //-1 for the '\0'-Byte
{
fputs("Input too long, exit\n",stderr);
exit(1);
}
//Are you sure you don't need error handling for read_next_char()?
buffer[i] = read_next_char();
buffer[i+1]='\0'; //End the string with a '\0'-Byte
}
Related
How to add element from string character array to another character array by pointers in c? below I've given code, please correct it and suggest anything because I didn't got a satisfied answer, I just want to same string in 'copy' array from 'buffer' array by only using there pointers?
char buffer[5] = "stop"; // Buffer character array
char copy[5]; // Copy character empty array
// Pointers
char *buffer_ptr, *copy_ptr;
buffer_ptr = buffer;
copy_ptr = copy;
int i;
for ( i = 0; i < 4; i++)
{
strncpy(copy_ptr, buffer_ptr, 1); // Here I want to copy string from buffer_pointer to copy_ptr
buffer_ptr = buffer_ptr + 1; // Here buffer_pointer pointer address is up by 1
copy_ptr = copy_ptr + 1; // Here copy_pointer pointer address is up by 1
}
printf("%s\n", copy);
return 0;
}
It almost looks like you are trying to invent a string manipulation method that already exists in standard code. You actually are utilizing the "strcpy" function in your code. Following is a simplified version of what I believe you are attempting to do.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int main()
{
char buffer[5] = "stop"; // Buffer character array
char copy[5]; // Copy character empty array
strcpy(copy, buffer);
printf("%s\n", copy);
return 0;
}
If, for some reason, you need to manipulate the data from your "buffer" string before the characters are placed into the "copy" string (e.g. make upper or lower case), you could utilize a method as follows.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int main()
{
char buffer[5] = "stop"; // Buffer character array
char copy[5]; // Copy character empty array
for (int i = 0; i < strlen(buffer); i++)
{
/* If needed, some processing could be done to the buffer character */
copy[i] = buffer[i];
}
printf("%s\n", copy);
return 0;
}
I hope that gives you some food for thought.
Regards.
For starters the array buffer contains 5 characters including the terminating zero character '\0' of the string literal "stop"
char buffer[5] = "stop"; // Buffer character array
So if you are going to copy character by character then the condition of the for loop should be written like
for ( i = 0; i < 5; i++)
^^^^^
Also if you are going to use pointers to copy a string in an array then the variable i is redundant.
Calling the function strncpy to copy only one character looks unnatural.
You could just write the for loop for example the following way
#include <stdio.h>
int main(void)
{
char buffer[5] = "stop"; // Buffer character array
char copy[5]; // Copy character empty array
for ( char *buffer_ptr = buffer, *copy_ptr = copy;
( *copy_ptr++ = *buffer_ptr++ ) != '\0'; );
printf("%s\n", copy);
}
You could move the for loop in a separate function as for example
#include <stdio.h>
char * string_copy( char *s1, const char *s2 )
{
for ( char *p = s1; *p++ = *s2++; );
return s1;
}
int main(void)
{
char buffer[5] = "stop"; // Buffer character array
char copy[5]; // Copy character empty array
puts( string_copy( copy, buffer ) );
}
The program output is
stop
I am trying to read a file and store every word into a dynamically allocated 2D array. The size of the input file is unknown.
I am totally lost and don't know how I could "fix/finish" the program.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int main(void) {
char filename[25];
printf("Input the filename");
scanf("%s", filename);
fileConverter(filename);
}
int fileConverter(char filename[25]) {
//int maxLines = 50000;
//int maxWordSize = 128;
//char words[maxLines][maxWordSize];
//char **words;
char **arr = (char**) calloc(num_elements, sizeof(char*));
for ( i = 0; i < num_elements; i++ ) {
arr[i] = (char*) calloc(num_elements_sub, sizeof(char));
}
FILE *file = NULL;
int amountOfWords = 0;
file = fopen(filename, "r");
if(file == NULL) {
exit(0);
}
while(fgets(words[amountOfWords], 10000, file)) {
words[amountOfWords][strlen(words[amountOfWords]) - 1] = "\0";
amountOfWords++;
}
for(int i = 0; i < amountOfWords; i++) {
printf("a[%d] = ", i);
printf("%s\n", words[i]);
}
printf("The file contains %d words and the same amount of lines.\n", amountOfWords);
return amountOfWords;
The main challenges for this kind of problem are
reallocating the array of strings as the program reads new words, and
handling words that are larger than the buffer used by fgets.
The general approach for these kind of parsing problems, is to design a state machine. The state machine here has two states:
The current character is whitespace. Action: Continue reading whitespace until we reach the end of the buffer, or until we land on a non-whitespace character, in which case we switch to state 2.
The current character is non-whitespace (i.e. a word). Action: Continue reading non-whitespace until we reach the end of the buffer, or until we land on a whitespace character, in which case we copy the word we just read to the array of strings and switch to state 1.
Particularly difficult is the case in which we are in state 2 and reach the end of the buffer. This means that this word spans multiple buffers. To accommodate for this, we deviate slightly from a direct state machine implementation. State 2 is slightly different, depending on if we are reading a new word or continuing one that was started in a previous buffer.
We now keep track of wordSize. If we start reading from the start of a buffer, but wordSize is not 0, then we know we are continuing a previous word and we know what size it was for the realloc we need.
Below is one possible implementation. All the work is done in the wordArrayRead function. Walking through it from the top of the function:
First we declare the variables that we need across lineBuffer reads: an index for the word itself and the length of the word we are currently reading, followed by the declaration of the buffer itself. The outside loop repeatedly reads using fgets until we have exhausted the input.
We start reading at index 0 and stop at the null-terminator. The first if-statement checks if we should be in state 2: either the current character is the start of a word or we were already reading a word.
State 2
The index wordStartIdx stays at the first character of the word (segment) and we walk the wordEndIdx to the end of the word (segment) or to the end of the buffer.
We then check if we need to increase the size of the array of strings. Here we increase it to 2 times + 1 the previous size to avoid frequent reallocations.
We set a boolean value, indication whether we have reached the end of a word. If we have, we need to allocate for and write the null-terminator at the end of the string.
If wordLength == 0 it means we are reading a new word and have to allocate memory for it for the first time. If wordLength != 0, we have to reallocate to append to an existing word.
We copy the word (segment) currently in the lineBuffer to the array of strings.
Now, we do some bookkeeping. If we reached the end of a word, we write the null-terminator, increment the index to point to the next word location and reset wordLength. If this wasn't the case, we only increment the wordLength with the length of the segment we just read. Finally, we update wordStartIdx, which still points to the start of the word, to point to the end of the word, so we can continue iterating over the buffer.
State 1
Having finishing the State 2 processing, we go into State 1 which has only two lines. It simply advances the index until we land at non-whitespace. Note that the null-terminator of the lineBuffer ('\0') does not count as whitespace, so this loop will not continue past the end of the buffer.
After all input has been processed, we shrink the array of strings to the actual size of its data. This "corrects" the allocation policy of increasing the size by 2n+1 each time it wasn't large enough.
#include <assert.h>
#include <ctype.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
// BUFFER_SIZE must be >1U
#define BUFFER_SIZE 1024U
struct WordArray
{
char **words;
size_t numberOfWords;
};
static struct WordArray wordArrayConstruct(void);
static void wordArrayResize(struct WordArray *wordArray, size_t const newSize);
static void wordArrayDestruct(struct WordArray *wordArray);
static void wordArrayRead(FILE *restrict stream, struct WordArray *wordArray);
static char *reallocStringWrapper(char *restrict str, size_t const newSize);
static void wordArrayPrint(struct WordArray const *wordArray);
int main(void)
{
struct WordArray wordArray = wordArrayConstruct();
wordArrayRead(stdin, &wordArray);
wordArrayPrint(&wordArray);
wordArrayDestruct(&wordArray);
}
static void wordArrayRead(FILE *restrict stream, struct WordArray *wordArray)
{
size_t wordArrayIdx = 0U;
size_t wordLength = 0U;
char lineBuffer[BUFFER_SIZE];
while (fgets(lineBuffer, sizeof lineBuffer, stream) != NULL)
{
size_t wordStartIdx = 0U;
while (lineBuffer[wordStartIdx] != '\0')
{
if (!isspace(lineBuffer[wordStartIdx]) || wordLength != 0U)
{
size_t wordEndIdx = wordStartIdx;
while (!isspace(lineBuffer[wordEndIdx]) && wordEndIdx != BUFFER_SIZE - 1U)
++wordEndIdx;
if (wordArrayIdx >= wordArray->numberOfWords)
wordArrayResize(wordArray, wordArray->numberOfWords * 2U + 1U);
size_t wordSegmentLength = wordEndIdx - wordStartIdx;
size_t foundWordEnd = wordEndIdx != BUFFER_SIZE - 1U; // 0 or 1 bool
// Allocate for a new word, or reallocate for an existing word
// If a word end was found, add 1 to the size for the '\0' character
char *dest = wordLength == 0U ? NULL : wordArray->words[wordArrayIdx];
size_t allocSize = wordLength + wordSegmentLength + foundWordEnd;
wordArray->words[wordArrayIdx] = reallocStringWrapper(dest, allocSize);
memcpy(&(wordArray->words[wordArrayIdx][wordLength]),
&lineBuffer[wordStartIdx], wordSegmentLength);
if (foundWordEnd)
{
wordArray->words[wordArrayIdx][wordLength + wordSegmentLength] = '\0';
++wordArrayIdx;
wordLength = 0U;
}
else
{
wordLength += wordSegmentLength;
}
wordStartIdx = wordEndIdx;
}
while (isspace(lineBuffer[wordStartIdx]))
++wordStartIdx;
}
}
// All done. Shrink the words array to the size of the actual data
if (wordArray->numberOfWords != 0U)
wordArrayResize(wordArray, wordArrayIdx);
}
static struct WordArray wordArrayConstruct(void)
{
return (struct WordArray) {.words = NULL, .numberOfWords = 0U};
}
static void wordArrayResize(struct WordArray *wordArray, size_t const newSize)
{
assert(newSize > 0U);
char **tmp = (char**) realloc(wordArray->words, newSize * sizeof *wordArray->words);
if (tmp == NULL)
{
wordArrayDestruct(wordArray);
fprintf(stderr, "WordArray allocation error\n");
exit(EXIT_FAILURE);
}
wordArray->words = tmp;
wordArray->numberOfWords = newSize;
}
static void wordArrayDestruct(struct WordArray *wordArray)
{
for (size_t wordStartIdx = 0U; wordStartIdx < wordArray->numberOfWords; ++wordStartIdx)
{
free(wordArray->words[wordStartIdx]);
wordArray->words[wordStartIdx] = NULL;
}
free(wordArray->words);
}
static char *reallocStringWrapper(char *restrict str, size_t const newSize)
{
char *tmp = (char*) realloc(str, newSize);
if (tmp == NULL)
{
free(str);
fprintf(stderr, "Realloc string allocation error\n");
exit(EXIT_FAILURE);
}
return tmp;
}
static void wordArrayPrint(struct WordArray const *wordArray)
{
for (size_t wordStartIdx = 0U; wordStartIdx < wordArray->numberOfWords; ++wordStartIdx)
printf("%zu: %s\n", wordStartIdx, wordArray->words[wordStartIdx]);
}
Note: This program reads input from stdin, as Unix/Linux utilities typically do. Use input redirection to read from a file, or provide a file descriptor to the readWordArray function.
to allocate dynamic 2D array you need:
void allocChar2Darray(size_t rows, size_t columns, char (**array)[columns])
{
*array = malloc(rows * sizeof(**array));
}
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 am writing a program that encodes text such that it can be put into a URL. I have the user inputting a string and if it contains special characters (#, %, &, ?, etc.) to replace them with their corresponding character codes (%23, %25, %26, %3F, etc.). The problem is that the special characters are only of length 1 and the codes are of length 3. The codes end up replacing characters after the special one. This is the code I am using to do the replacement.
char *p = enteredCharStr;
while ((p = strstr(p, specialCharArr[x])) != NULL )
{
char *substr;
substr = strstr(enteredCharStr, specialChar[x]);
strncpy(substr, charCodesArr[x], 3);
p++;
}
Example output from using my program with input: "this=this&that"
this%3Dis%26at
I would like the output to be:
this%3Dthis%26that
Any idea on how to implement what I am trying to do in C (no libraries)?
One way to approach this problem would be to allocate a second string that is three times as large as enteredCharStr and copy the characters over one by one and when you see special character write the replaement instead. You want it to be three times as large since in the worst case you need to replace nearly all the characters.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int isspecial(int c){
static char table[] = "#%&?=<>"; //add etc..
return strchr(table, c) ? 1 : 0;
}
char *encode(const char *s){
size_t capa = 1024;
char *buff=malloc(capa*sizeof(char));
size_t size = 0;
for(;*s;++s){
if(size + 3 > capa){
capa += 32;
buff = realloc(buff, capa*sizeof(char));
}
if(isspecial(*s)){
size+=sprintf(buff+size, "%%%02x", *s);
} else {
size+=sprintf(buff+size, "%c", *s);
}
}
if(size == capa){
buff=realloc(buff, (size+1)*sizeof(char));
}
buff[size++]='\0';
return realloc(buff, size*sizeof(char));
}
int main(void){
char *enteredCharStr = "this=this&that";
char *p = encode(enteredCharStr);
printf("%s\n", p);
free(p);
return 0;
}
You need to make a new string. Here's an example:
char *str = "abc$ddd";
char *p = str;
char *buf = malloc(strlen(str)+1);
char *pbuf = buf;
while(*p) {
if(*p != '$') *pbuf ++ = *p;
p++;
}
It will copy from str to buf all non-$,byte per byte.
Note that in your case,you need to perform the right computation of size of new string.
A C 'string' is a fixed-size array of characters, and therefore there is no built-in notion of insertion. You're effectively asking how to insert n characters into the middle of an array.
One strategy come to mind:
To insert a string of length x at position i of an array of length n:
Resize the array to size n+x (using something like realloc).
Shuffle every character beyond position i to position i+x.
Write your string into the x positions now freed by this shuffle operation.
Alternatively, allocate a new array that is big enough to hold your target string (i.e., with all the substitutions applied), and then write your result into that by copying from the target array until you encounter a character you'd like to replace, then copy from the replacement string, then continue reading from the original source array.
I'm copying characters over one by one, and if I see a special character, (In this code only "#")
I copy in 3 characters, incrementing the index into the output buffer by 3.
You can also do something smarter to guess the buffer size, and perhaps loop over the entire operation, doubling the size of the buffer each time it overruns.
#include<stdio.h>
#include<stdlib.h>
int main(int argc, char* argv[]){
if (argc != 2) {
exit(1);
}
char* input = argv[1];
int bufferSize = 128;
char* output = malloc(bufferSize);
int outIndex = 0;
int inIndex = 0;
while(input[inIndex] != '\0'){
switch (input[inIndex])
{
case '#':ยท
if(outIndex + 4 > bufferSize){
// Overflow, retry or something.
exit(2);
}
output[outIndex] = '%';
output[outIndex+1] = '2';
output[outIndex+2] = '3';
outIndex = outIndex + 3;
inIndex = inIndex + 1;
break;
// Other cases
default:
if(outIndex + 2 > bufferSize){
exit(2);
}
output[outIndex] = input[inIndex];
outIndex = outIndex + 1;
inIndex = inIndex + 1;
break;
}
}
output[outIndex] = '\0';
printf("%s\n", output);
return 0;
}
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;
}