Char concatenation and memory reallocation - c

I am trying to concatenate single digits to a string:
include <stdio.h>
include <stdlib.h>
include <string.h>
int main() {
char *test="";
int i;
for (i = 0; i < 10; i++)
char *ic;
ic = malloc(2);
sprintf(ic, "%d", i);
// printf("%d\n", strlen(test));
if (strlen(test) == 0)
test = malloc(strlen(ic));
strcpy(test, ic);
} else {
realloc(test, strlen(test) + strlen(ic));
strcat(test, ic);
}
}
printf("%s\n", test);
// printf("%c\n", test);
free(test);
test = NULL;
return 0;
}
My goal is for the result of the final printf ("%s", test) be 0123456789.

Remember that strings are terminated with null characters. When you allocate memory for a string, you must add an extra byte for the null. So you'll need to add 1 to each of your malloc() and realloc() calls. For example:
test = malloc(strlen(ic) + 1);
Remember, also, that realloc() is allowed to "move" a variable to a new location in memory. It may need to do that in order to find enough contiguous unallocated space. It can also return NULL if it's unable to allocate the memory you've requested, so you should call it like this:
char *new_mem = realloc(test, strlen(test) + strlen(ic) + 1);
if (new_mem == NULL) {
// Not enough memory; exit with an error message.
} else {
test = new_mem;
}

A few issues:
char *test=""; - you point test to a constant C string. You don't write to it, but it's dangerous and will compile in C++. The type of "" is const char*.
strlen returns the length of the string not the buffer size. You need to add +1 to include the NULL character. This is your biggest issue.
A short known fixed size small buffer like ic should be allocated on the stack. A simple char array. You also forgot to free() it.

Related

I am trying to generate 1 GB of data by concatenating strings in C

Below is the code I have so far. It is giving segmentation fault after a couple of iterations. Can anyone help me to figure out the problem?
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int main()
{
char *str; // 1GB = 1073741824 bytes
char *temp;
long long int i;
str = (char *)malloc(1073741824);
strcpy(str,"a");
for(i = 1; i <= 73741824;i = i*2)
{
strcat(str,str);
}
free(str);
}
You are calling strcat() with the same string as both arguments, which is an error. See the manual page:
The strings may not overlap, and the dest string must have enough space for the result.
You're experiencing some undefined behavior! If you read the description of strcat, it mentions: "If copying takes place between objects that overlap, the behavior is undefined," (source).
If you think about it, it first copies the first byte of str to the null byte of str, and continues until the null byte. Do you see the problem? You overwrite it, so you will keep copying bytes until you encounter a garbage null byte.
The way around this is to not have the same source and destination string. Also, why are you iterating until 73741824? If you want a 1GB string, you should iterate until 1073741824. Also keep in mind building the string this way is no more efficient than just concatenating "a" onto your string ~1 billion times. Knowing that, that's what we'll end up doing to solve our problem.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int main() {
char *str; // 1GB = 1073741824 bytes
char *temp;
long long int i;
const size_t GB = 1073741824;
str = (char *)malloc(GB);
strcpy(str, "a");
for(i = 1; i < GB; i++) {
strcat(str + i, "a");
}
free(str);
}
Edit: if you prefer the original algorithm, I've fixed that as well. Just make the corresponding changes. This will avoid copying to any overlapping memory, and therefore, avoid any undefined behavior.
for(i = 1; i < GB; i *= 2) {
str[i - 1] = '\0';
strcat(str + i, str);
str[i - 1] = 'a';
str[2 * i - 1] = 'a';
str[2 * i] = '\0';
}
I thought this one should be closed, since the "what happens if string is concatened to itself" question is already answered here: Concatenating string with itself two times give segmentation fault.
However, since the close vote was rejected and there are number of other issues, I've fixed the code. This algorithm uses 2*SIZE memory, but it's significantly faster than the one in kamoroso94's answer (which uses less memory) and remains closer to the question author's idea.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define SIZE (1024 * 1024 * 1024) // convenient way how to define 1GB
int main()
{
char *str;
char *temp;
long long int i;
// don't forget to allocate space for the terminating character!
str = malloc(SIZE + 1); // no need to typecast the result malloc()
temp = malloc(SIZE + 1);
// don't forget to check for allocation failures
if (str == NULL || temp == NULL) {
printf("malloc failed\n");
return -1;
}
strcpy(temp, "a");
for(i = 1; i <= SIZE; i *= 2) {
// concatenate the buffer to the string
strcat(str, temp);
// copy the whole string to the temporary buffer
strcpy(temp, str);
}
printf("length of s = %u\n", strlen(str));
free(str);
free(temp);
}

Stripping a sentence for only it's alpha characters

I'm trying to solve a code to strip a sentence down only to it's alpha character, using the following code, but the code always gives me a runtime error(The commented parts are steps I had taken to figure out the solution).
[Ex: Test'sen- tence should print Testsentence]
#include <stdio.h>
#include <stdlib.h>
#include <ctype.h>
#define BUFFER_LEN 1000
#define BUFFER_INCR 15
int main(void)
{
int buffer_length = BUFFER_LEN;
char *pString = malloc(BUFFER_LEN);/* initial array */
char *pTemp_start = pString;
long long int String_len = 0;
char *pTemp = NULL;
int copy = 0;
int count = 0;/*delete this after check*/
while((*pString++ = getchar()) != '\n')
{
String_len = pString - pTemp_start;
printf("\nThe character you inputted is: %c", *(pString+count++));
//getchar();
if(String_len == (buffer_length - 1))/*reserve one for newline*/
{
buffer_length += BUFFER_INCR;
pTemp = realloc(pString, buffer_length);/*reallocate space for
15 more chars.*/
pTemp_start = pTemp - String_len;
pString = pTemp;
free(pTemp);
pTemp = NULL;
if(!pString)
{
printf("The space couldn't be allocated");
return 1;
}
}
}
/*checks that can be done for addresses*/
//printf("\nThe length of the string is: %lld", pString - pTemp_start);
*(--pString) = '\0';
//printf("\nThe charcter at the end is: %d", *(pString + String_len - 1));
//printf("\nThe character at the mid is: %d", *(pString + 2));
printf("The input string is: %c", *pString);
/*code to remove spaces*/
for(int i = 0; i < (String_len + 1); i++)
{
if((isalnum(pString[i])))
{
*(pString + copy++) = *(pString +i);
}
}
*(pString + copy) = '\0';/*append the string's lost null character*/
printf("\nThe stripped string is: \n%s", pString);
return 0;
}
The code simply doesn't print anything that's inputted.
So you've got a conflict in your code between this line
while((*pString++ = getchar()) != '\n')
and lines like the following.
pTemp = realloc(pString, buffer_length);
The first line I've quoted is incrementing the position of pString within your allocated memory, but the second one is acting as if pString is still pointing to the start of it. realloc() won't work unless pString is pointing to the start of the allocated memory. You're then not checking the results of the realloc() call, assigning the new memory block to pString and then freeing the newly allocated memory. So you're definitely going to have unexpected results.
You also have to remember that stdin is buffered, so your code will wait until it's got an entire line to read before doing anything. And stdout is also buffered, so only lines that end in a \n will be output. So you probably want to have the following...
printf("The character you inputted is: %c\n", *pString);
...or something similar bearing in mind the issues with how you're using pString.
realloc(pString,...) does not add an allocated block, it replaces the one being reallocated (in this case, pString). So pString isn't (necessarily) a valid pointer after that call. Worse, you then free(pTemp), so you no longer have anything allocated.

Getting string with C function

I need to get strings dynamically but as I need to get more than one string, I need to use functions. So far I wrote this
(I put //**** at places i think might be wrong)
char* getstring(char *str);
int main() {
char *str;
strcpy(str,getstring(str));//*****
printf("\nString: %s", str);
return 0;
}
char* getstring(char str[]){//*****
//this part is copy paste from my teacher lol
char c;
int i = 0, j = 1;
str = (char*) malloc (sizeof(char));
printf("Input String:\n ");
while (c != '\n') {//as long as c is not "enter" copy to str
c = getc(stdin);
str = (char*)realloc(str, j * sizeof(char));
str[i] = c;
i++;
j++;
}
str[i] = '\0';//null at the end
printf("\nString: %s", str);
return str;//******
}
printf in the function is working but not back in main function.
I tried returning void, getting rid of *s or adding, making another str2 and tring to strcpy there or not using strcpy at all. Nothing seems to working. Am I misssing something? Or maybe this is not possible at all
//Thank you so much for your answers
Getting the string part can be taken from this answer. Only put a \n as input to the getline funtion.
char * p = getline('\n');
Three things :-
don't cast malloc, check if malloc/realloc is successful and sizeof is not a function.
The problem is not with the function that you are using, but with the way you try copying its result into an uninitialized pointer.
Good news is that you don't have to copy - your function already allocates a string in dynamic memory, so you can copy the pointer directly:
char *str = getstring(str);
This should fix the crash. A few points to consider to make your function better:
main needs to free(str) when it is done in order to avoid memory leak
Store realloc result in a temporary pointer, and do a NULL check to handle out-of-memory situations properly
There are two things to take away from the lesson as it stands now:
(1) You should have one way of returning the reference to the new string, either as an argument passed by reference to the function OR as a return value; you should not be implementing both.
(2) Because the subroutine your teacher gave you allocates memory on the heap, it will be available to any part of your program and you do not have to allocate any memory yourself. You should study the difference between heap memory, global memory, and automatic (stack) memory so you understand the differences between them and know how to work with each type.
(3) Because the memory is already allocated on the heap there is no need to copy the string.
Given these facts, your code can be simplified to something like the following:
int main() {
char *str = getstring();
printf( "\nString: %s", str );
return 0;
}
char* getstring(){
.... etc
Going forward, you want to think about how you de-allocate memory in your programs. For example, in this code the string is never de-allocated. It is a good habit to think about your strategy for de-allocating any memory that you allocate.
Let's simplify the code a bit:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
char* getstring()
{
char c = 0;
int i = 0, j = 2;
char *str = NULL;
if ((str = (char*) malloc(sizeof(char))) == NULL)
return NULL;
printf("Input String: ");
while (c = getc(stdin)) {
if (c == '\n') break;
str = (char*) realloc(str, j * sizeof(char));
str[i++] = c;
j++;
}
str[i] = '\0';
printf("getstring() String: %s\n", str);
return str;
}
int main()
{
char *str = getstring();
printf("main() String: %s\n", str);
free(str);
return 0;
}
Then execute:
$ make teststring && ./teststring
cc teststring.c -o teststring
Input String: asdfasfasdf
getstring() String: asdfasfasdf
main() String: asdfasfasdf

reading a file of strings to a multidimensional array to access later

I am really having a problem understanding dynamically allocated arrays.
I am attempting to read a text file of strings to a 2d array so I can sort them out later. right now as my code stands it throws seg faults every once in a while. Which means I'm doing something wrong. I've been surfing around trying to get a better understanding of what malloc actually does but I want to test and check if my array is being filled.
my program is pulling from a text file with nothing but strings and I am attempting to put that data into a 2d array.
for(index = 0; index < lines_allocated; index++){
//for loop to fill array 128 lines at a time(arbitrary number)
words[index] = malloc(sizeof(char));
if(words[index] == NULL){
perror("too many characters");
exit(2);
}
//check for end of file
while(!feof(txt_file)) {
words = fgets(words, 64, txt_file);
puts(words);
//realloc if nessesary
if (lines_allocated == (index - 1)){
realloc(words, lines_allocated + lines_allocated);
}
}
}
//get 3rd value placed
printf("%s", words[3]);
since this just a gist, below here ive closed and free'd the memory, The output is being displayed using puts, but not from the printf from the bottom. an ELI5 version of reading files to an array would be amazing.
Thank you in advance
void *malloc(size_t n) will allocate a region of n bytes and return a pointer to the first byte of that region, or NULL if it could not allocate enough space. So when you do malloc(sizeof(char)), you're only allocating enough space for one byte (sizeof(char) is always 1 by definition).
Here's an annotated example that shows the correct use of malloc, realloc, and free. It reads in between 0 and 8 lines from a file, each of which contains a string of unknown length. It then prints each line and frees all the memory.
#include <stdio.h>
#include <stdlib.h>
/* An issue with reading strings from a file is that we don't know how long
they're going to be. fgets lets us set a maximum length and discard the
rest if we choose, but since malloc is what you're interested in, I'm
going to do the more complicated version in which we grow the string as
needed to store the whole thing. */
char *read_line(void) {
size_t maxlen = 16, i = 0;
int c;
/* sizeof(char) is defined to be 1, so we don't need to include it.
the + 1 is for the null terminator */
char *s = malloc(maxlen + 1);
if (!s) {
fprintf(stderr, "ERROR: Failed to allocate %zu bytes\n", maxlen + 1);
exit(EXIT_FAILURE);
}
/* feof only returns 1 after a read has *failed*. It's generally
easier to just use the return value of the read function directly.
Here we'll keep reading until we hit end of file or a newline. */
while ('\n' != (c = getchar())) {
if (EOF == c) {
/* We return NULL to indicate that we hit the end of file
before reading any characters, but if we've read anything,
we still want to return the string */
if (0 == i) return NULL;
break;
}
if (i == maxlen) {
/* Allocations are expensive, so we don't want to do one each
iteration. As such, we're always going to allocate more than
we need. Exactly how much extra we allocate depends on the
program's needs. Here, we just add a constant amount. */
maxlen += 16;
/* realloc will attempt to resize the memory pointed to by s,
or copy it to a newly allocated region of size maxlen. If it
makes a copy, it will free the old version. */
char *p = realloc(s, maxlen + 1);
if (!p) {
/* If the realloc fails, it does not free the old version, so we do it here. */
free(s);
fprintf(stderr, "ERROR: Failed to allocate %zu bytes\n", maxlen + 1);
exit(EXIT_FAILURE);
}
s = p;//set the pointer to the newly allocated memory
}
s[i++] = c;
}
s[i] = '\0';
return s;
}
int main(void) {
/* If we wanted to, we could grow the array of strings just like we do the strings
themselves, but for brevity's sake, we're just going to stop reading once we've
read 8 of them. */
size_t i, nstrings = 0, max_strings = 8;
/* Each string is an array of characters, so we allocate an array of char*;
each char* will point to the first element of a null-terminated character array */
char **strings = malloc(sizeof(char*) * max_strings);
if (!strings) {
fprintf(stderr, "ERROR: Failed to allocate %zu bytes\n", sizeof(char*) * max_strings);
return 1;
}
for (nstrings = 0; nstrings < max_strings; nstrings++) {
strings[nstrings] = read_line();
if (!strings[nstrings]) {//no more strings in file
break;
}
}
for (i = 0; i < nstrings; i++) {
printf("%s\n", strings[i]);
}
/* Free each individual string, then the array of strings */
for (i = 0; i < nstrings; i++) {
free(strings[i]);
}
free(strings);
return 0;
}
I haven't looked too closely so I could be offering an incomplete solution.
That being said, the error is probably here:
realloc(words, lines_allocated + lines_allocated);
realloc if succesful returns the new pointer, if you're lucky it can allocate the adjacent space (which wouldn't cause a segfault).
words = realloc(words, lines_allocated + lines_allocated);
would solve it, although you probably need to check for errors.

how to make a copy of string into a dynamically allocated character array of the appropriate size?

char input[1000];
I want to copy input into a dynamically allocated character array, how do I approach this problem.
So far I have used strncpy, but get lots of errors.
Are you looking for something like this:
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
int main() {
int i;
char input[1000] = "Sample string";
char *in = malloc(1000 * sizeof(char)); // use dynamic number instead of 1000
strcpy(in, input);
for (i = 0; i < 5; ++i) { // intentionally printing the first 5 character
printf("%c", in[i]);
}
}
The output is:
Sampl
Edit: In C++ the cast is required for malloc, so I write:
(char *)malloc(1000 * sizeof(char))
But in C, never cast the result of malloc().
What you can do is just use strcpy() offer by C string.h after dynamically allocating memory to your array, as shown:
char *input = malloc(1000*sizeof(char));
and if the string you are trying to copy to variable input exceeds the allocated memory size (strlen > 999: don't forget! String has a null terminator '\0' that takes up the additional 1 char space), just realloc as shown:
input = realloc(input, 1000*2*sizeof(char));
/* check if realloc works */
if (!input) {
printf("Unexpected null pointer when realloc.\n");
exit(EXIT_FAILURE);
}

Resources