C Programming - Changing chars of a string array element [duplicate] - c

This question already has answers here:
Closed 10 years ago.
Possible Duplicate:
Problem with processing individual strings stored in an array of pointers to multiple strings in C
Ok so I'm trying to change a char of a string to another char in C. The thing is, each string is an element of a 1D array so essentially all together its a 2D array because a string itself is an array of chars. Anyways I have a problem creating code to do this. Is it even possible to do this? Any help is appreciated.
Here's the code:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int main ()
{
int i, size;
char **a;
a=(char**)malloc(sizeof(char*));
printf("Enter the size of the array:");
scanf("%d", &size);
for(i=0;i<size;i++){
a[i]=(char*)malloc(sizeof(char)*8);
}
a[3]="Read";
while(*(a[3])!='\0'){
if(*(a[3]) == 'e'){
*(a[3]) = 'r';
}
}
printf("%s\n", a[3]);
system("pause");
return 0;
}

a=(char**)malloc(sizeof(char*));
printf("Enter the size of the array:");
scanf("%d", &size);
for(i=0;i<size;i++){
a[i]=(char*)malloc(sizeof(char)*8);
}
Nope. You've allocated 1 char*. Then you treat it like it's size elements. You need to allocate size * sizeof(char*) bytes. (Note that this multiplication could also overflow.)
a[3]="Read";
Bad times. You are overwriting a[3] (which previously pointed to an allocation of 8 chars) with the location of a string literal, "Read". This leaks the previous allocation and also puts a non-modifiable string into a[3]. You should look into strncpy et al. for this.

You didn't allocate enough space for a. Instead of
a=(char**)malloc(sizeof(char*));
you need
a=(char**)malloc(sizeof(char*)*size);
and obviously this must move to be after size has been read.
Once you sort that rather mundane problem out the fundamental problem is here:
a[3]="Read";
This makes the pointer a[3] point at a literal which cannot be modified. Instead you need to copy the contents of that literal into a[3]. Like this:
strcpy(a[3], "Read");
You must understand that a[3]=... assigns just the pointer a[3] and does not modify the string to which a[3] points.
Now, your code will obviously be in error if size is less than 4 since then a[3] would be out of bounds, but I guess a[3] is just transient while you debug this.
Your while loop is all wrong. Judging from your comments you want something like this:
char *p = a[3];
while (*p != '\0')
{
if (*p == 'e')
*p = 'r';
p++;
}
No need to cast the return value of malloc in C, so remove the casts. sizeof(char) is always equal to 1 so you can remove that too.

This:
a=(char**)malloc(sizeof(char*));
allocates space for one string. What you probably intend is something like:
char **a = NULL;
size_t number_of_strings = 8; /* for argument's sake */
a = malloc(number_of_strings * sizeof(char*));
if (!a)
return NOT_ENOUGH_MEMORY_ERROR;
At this point, you can dereference elements of a, e.g., a[3]. You'll still want to allocate space for those guys too:
char *staticStr = "Read";
a[3] = malloc(strlen(staticStr) + 1);
strncpy (a[3], staticStr, strlen(staticStr) + 1);
Start with that and see if rethinking how you're allocating memory will help you fix your other bugs.
Some notes:
You don't need to cast the result of malloc in C
You don't need to use sizeof(char) for allocating memory, which is always 1
You should be using a corresponding free() for each a[i] and for a itself, to prevent memory leaks

I see another problem, when you allocate memory for the:
a = (char **) malloc(sizeof(char *));
You are allocating memory for just one position, but you are using size positions. Then your code should be:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int main ()
{
int i, size;
char **a;
char *ptr;
printf("Enter the size of the array:");
scanf("%d", &size);
a=(char**)malloc(size * sizeof(char*));
for(i=0;i<size;i++){
a[i]=(char*)malloc(sizeof(char)*8);
}
strcpy(a[3], "Read");
ptr=a[3];
while(*ptr!='\0'){
if(*ptr == 'e'){
*ptr = 'r';
}
ptr++;
}
printf("%s\n", a[3]);
system("pause");
return 0;
}
and of course, you need to free the allocated memory.
In your while when you try to change the 'e' to 'r' you are always point to the same char. You need a new pointer to walk throw the array.

Your while loop doesn't do anything.
while(*(a[3])!='\0'){
if(*(a[3]) == 'e'){
*(a[3]) = 'r';
}
}
It doesn't advance the pointer, it just keeps it at the first position.
A more proper-ish way would be to make a temporary pointer and use it to walk the string
char *temp = a[3];
while (*temp != '\0') {
if (*temp == 'e') *temp = 'r';
temp++;
}

Related

How to dynamically allocate string using void function?

First of all Thanks for visiting my question... :)
I am interested in competitive programming, so I daily do some amount of problem-solving, however, I only know C language at a decent level, and I often face problems while dynamically allocating something as usual, especially for strings and 2D arrays.
But I somehow manage to find ways (thanks to StackOverflow), for example, I wanted to create a function that scans string dynamically until the user enters space or new line, so I came up with the solution below and it works perfectly:
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
// scanf("%[^\n]%*c", str);
char *create_string(char *ptr)
{
ptr = (char *)malloc(0 * sizeof(char));
unsigned int size = 0;
char c = 0;
while (1)
{
scanf("%c", &c);
if (c == 32 || c == 10)
{
break;
}
size++;
ptr = (char *)realloc(ptr, size * sizeof(char));
ptr[size - 1] = c;
}
ptr = (char *)realloc(ptr, (size + 1) * sizeof(char));
ptr[size] = '\0';
return ptr;
}
int main()
{
char *str;
str = create_string(str);
printf("%s", str);
printf("\n%lu", strlen(str));
return 0;
}
And now for curiosity purposes, I want to know how can I do this same thing using the void function?, something like:
char *str;
create_string(&str);
should start storing everything in the dynamic memory which is pointed by str.
Also, please if you have more knowledge to show in DMA for 2D array, then please show me it, feel free to give examples with different problems.
And also How can I stop scanning the string (which was allocated dynamically) with specific string ending? for example, scanning(any kind of scanning, i.e. int, bool, custom structures etc...) should stop if user enters string "STOP", Please feel free to give pictorial examples.
Because I am sure that this question is burning like a fire in beginner's and intermediate C programmers' minds.
As C passes arguments by value, to return something via an out parameter, you need to pass in a pointer to it. So to return a char * it would:
void create_string(char **s) {
*s = malloc(42);
}
Here is your refactored code. I changed the following:
Eliminate return value of update caller.
Initialize *ptr = malloc(1) for the trailing '\0'. It eliminates an unnecessary and implementation defined malloc(0). This also eliminates the (*ptr)[size] = ... which looks wrong as the last index is expected to be size - 1. Alternatively initialize it to NULL.
Use character constants instead of magic values (32, 10).
sizeof(char) is defined as 1 so leave it out.
Reduced scope of variable c.
free() memory allocated.
(cosmetic) Use size_t size instead of unsigned int size.
(cosmetic) Avoid the noise of casting casting void *.
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
void create_string(char **ptr) {
*ptr = malloc(1);
size_t size = 1;
for(;;) {
char c;
scanf("%c", &c);
if (c == ' ' || c == '\n') break;
(*ptr)[size-1] = c;
size++;
*ptr = realloc(*ptr, size);
}
(*ptr)[size-1] = '\0';
}
int main() {
char *str;
create_string(&str);
printf("%s\n", str);
printf("%zu\n", strlen(str));
free(str);
}
I didn't fix these issue:
Check return value of malloc(), realloc().
v = realloc(v, ...) is unsafe and will leak memory if realloc() fails. You need to do char *tmp = realloc(v,...); if(!tmp) { // err }; v = tmp;.
Check return value of scanf() otherwise you may be operating on uninitialized data.
Use scanf("%s", ..) instead of for(;;) { scanf("%c", ...). It's more efficient to allocate a chunk at a time instead of per byte.
If user enters ctrl-d (EOF) the program will go into an infinite loop.
It's good idea to separate i/o from logic (i.e. let caller do the scanf(). That way create_string() is much more reusable.

Convert int to string, then fill the array with the converted elements

Iam trying to fill array with numbers that i converted from int to string. The output iam trying to get is {"0", "1", "2"...} but my array is filled with the last number that i converted {"19", "19", "19"..} idk why is that. Could you please help me guys ?
My code:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int main() {
char *arr[20] = {};
for(int i = 0;i < 20;i++){
char str[20];
itoa(i, str, 10);
arr[i] = str;
}
for(int i = 0;i < 20;i++){
printf("%s\n", arr[i]);
}
}
Problem
char str[20]; arranges that str is a pointer to the first element of a chunk of memory containing 20 chars. Since the str is a local variable to the for loop, you cannot be sure what happens to that memory after the current iteration finishes. It is undefined behaviour.
With that in mind, think about what arr will be at the the end of the first for loop.
It will be an array of 20 pointers to some bit of memory. But you can no longer be sure what the memory contains. It may be, as in your case, that they all point to the same bit of memory, which is filled with the last string that itoa put there. This might not happen in general though.
Solution
To fix this, you should probably use malloc to allocate new memory for each string you want to keep, within the first for loop. The memory is then heap allocated, and you can be sure that each call to malloc will give you a chunk of unused memory, such that you won't be overwriting previous strings. Try for example:
for(int i = 0;i < 20;i++){
char *str = (char *) malloc(sizeof(char) * 20);
itoa(i, str, 10);
arr[i] = str;
}
Note that it is also good practice to explicitly free memory you have allocated with malloc.
char str[20]; creates a single location in memory where str is stored. It does not create a new location each time the loop is run.
arr[i] = str; points each element of arr at that one location, which by the end of the loop contains just "19".
Instead of arr[i] = str; you need to do something like strcpy(arr[i], str) to copy the current contents of str to the appropriate element of arr.
Also, as Scott Hunter pointed out, you should declare arr using char arr[20][20] to have 20 unique char arrays to actually write the strings into.
I tested the following code (changed itoa to sprintf) and it worked for me:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int main() {
char arr[20][20] = {};
for(int i = 0;i < 20;i++){
char str[20];
sprintf(str, "%i", i);
strcpy(arr[i], str);
}
for(int i = 0;i < 20;i++){
printf("%s\n", arr[i]);
}
}
Unrolling the loop, you get
arr[0] = str;
....
arr[1] = str;
....
arr[2] = str;
.... // etc
Which is basically:
arr[0] = arr[1] = arr[2] = arr[3] (...) = str;
So yeah, they all point to the same string. There is only one str.
There's also some undefined behaviour here. Firstly, all of your pointers arr[0] etc are being dereferenced here:
printf("%s\n", arr[i]);
when the thing they point to, str, has gone out of scope, there is no guarantee what might happen when you access it. Infact, the first "instance" of str goes out of scope at the end of the first iteration of the first loop. When you assign arr[1]=str, arr[0] is techincially invalid already. However, it likely that there is just one str that remains on the stack for the duration of the function, which would be consistent with the observed behaviour, but not guaranteed.
Try this
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int main() {
char arr[20][20] = {}; // Allocate the space to store the results
for(int i = 0;i < 20;i++){
char str[20]; // Temp store
itoa(i, str, 10);
strcpy (arr[i], str); // Copy the string from the temp store
// str goes out of scope NOW at the end of the loop, you cannot
// any pointer that points to it either outside this loop or the next time
// around the loop
}
// etc
you need to allocate memory for each place in the array, arr. you can do this on the stack or on the heap. In this approach i have allocated the strings on the heap. So i called malloc() for allocating buffers of size int (no need to allocate more).
In my approach i have used sprintf() from stdio.h to convert the numbers to string format.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define MAX_INT_DIGITS_NUM 20
int main() {
char* arr[20]; /*this is an array of 20 char pointers*/
for(int i = 0;i < 20;i++){
arr[i] = (char*)malloc(sizeof(char) * MAX_INT_DIGITS_NUM);
sprintf(arr[i], "%d", i);
}
for(int i = 0;i < 20;i++){
printf("%s\n", arr[i]);
/*now you need to free all previous allocated buffers*/
free(arr[i]);
}
return 0;
}
what is wrong with your code?
arr is only an array to char pointers! its not really holding string buffers that you can use for copy or scan to it! its only pointers that points to some address.
inside the for loop, you are declaring str buffer and you keep override it (itoa keeps copying to it) to the same place!! hence you exit the for loop in last iteration with only the last converted i!
now, just to aware you, after existing the for loop all the local variables marked by the os as released! so this can lead to memory corruption or override later in the program!
keep in mind that in my solution i always allocates MAX_INT_DIGITS_NUM bytes, no matter the i deget length. this is waste of memory! keep in mind that itoa() is not standard in C or ansi c!

Reducing the memory assigned to an array

Let's say I have an array of char containing a sentence, and I want to copy that sentence in a different array but filtering a certain character:
char a[] = "hello everybody";
char b[sizeof(a)];
char idontwantyou = 'e';
int it = 0;
for (int i=0; i<sizeof(a); ++i)
if (a[i]!=idontwantyou)
b[it++] = a[i];
I had to allocate the same amount of memory for b than the size of a because I don't know the size of the sentence without the undesired characters right?
Now, I have my b array with the sentence hllo vrybody'#·&¡` right? I mean, there is "trash" at the end of the array.
Is there any way I could "cut" the trash in the tail so the size of b is the same value than it?
I just copied b in a new array I defined as char c[sizeof(b)] but this doesn't seem like a good practise.
Maybe realloc in b would do what I want?
In-place elimination of unwanted character, and allocated array size reduction:
char *a = strdup("hello everybody");
char idontwantyou = 'e';
char *b = a;
char *c = a;
Eliminate unwanted character:
while(*b)
{
if(*b != idontwantyou)
{
*c=*b;
++c;
}
++b;
}
*c='\0';
Reduce the size of the allocated array:
b=realloc(a, strlen(a) + 1);
if(NULL == b)
/*Handle error... */;
a=b;
Test results:
printf("array = \"%s\"\n", a);
Output should be:
array = "hllo vrybody"
sizeof(b) would be equal to sizeof(a), because that is the actual size of b. To use realloc, you have to allocate b using malloc in the first place.
That would be done in a way similar to this:
char a[] = "hello everybody";
/* better use strlen here -- it will also work with char*, and not only with
statically allocated arrays */
char *b = malloc(strlen(a)+1);
/* your code here */
char *tmp = realloc(b, it);
if (!tmp) {
free(b);
/* some error here! */
} else {
b = tmp;
/* continue working with b */
}
There are some important bits in here:
You have to manually free b after you’re done, because it is allocated on the heap instead of the stack, and thus you have to release the memory on your own instead of it getting released automatically on the function exit.
The return value of realloc may be NULL. In that case, the old memory is still allocated and you have to do some kind of error handling (as sketched with the if).
If realloc succeeds, tmp points to the new memory area and b is invalid, which is why we override b with tmp.
Another way to do it is to run two passes over the string, one to count and one to copy.
You should evaluate the problem in terms of how much this operation matters in the
overall cost and cpu+memory profile of the program. Most likely, it hardly matters at all.
In which case, the simplest is probably the best.

Static array and dynamic array

char a[10];
scanf("%s",a);
int i=0;
while(a[i]!='\0')
printf("\n%c",a[i++]); //similar to printf("%s",a);
char *b;
b=malloc(10*sizeof(char));
scanf("%s",b);
i=0;
while((b+i)!='\0')
printf("\n%c",*(b+i++)); //not similar to printf("%s",a);
For input "abcd", the first loop prints a[] is it would be with printf(). But the same is not true for *b.
Second loops continues for too many until it encounters a '\0'.
So, does this mean '\0' is appended at the end of character strings automatically but not at the end of char type pointers?
And whose job is it to append this '\0'? Compiler's?
You forgot to dereference the pointer you get with b+i. It should be:
while (*(b + i) != '\0') // or while (b[i] != '\0') or while(b[i])
b + i just gets you an address, you have to dereference it to actually look at what the memory is pointing at and see if it's the NUL-terminator. The x[y] notation is equivalent to *(x + y).
Also don't forget to free the memory you allocated with malloc.
Dereferencing issue.
In the line (b+i) should be replaced with either:
*(b+i)
or
b[i]
Additionally, if you are just taking in strings, you should consider using fgets() instead of scanf, as it can help you avoid the user typing in too many characters and crashing your program.
Finally, you might consider using calloc() instead of malloc() as it automatically sets the contents of the array you allocate to be all-zeros rather than random garbage.
As an example:
#include <stdio.h>
#define MAX_BUFFER_LENGTH
int main(void) {
char a[MAX_BUFFER_LENGTH];
char *b;
fgets(a,MAX_BUFFER_LENGTH,stdin);
int i=0;
while(a[i]!='\0') {
printf("\n%c",a[i++]);
}
b=calloc(MAX_BUFFER_LENGTH,sizeof(char));
fgets(b,MAX_BUFFER_LENGTH,stdin);
i=0;
while(*(b+i)!='\0') {
printf("\n%c",*(b+i++));
}
// Done
return 0;
}
This is a much safer way to approach the problem you are solving.
Good luck!

String concatenation without strcat in C

I am having trouble concatenating strings in C, without strcat library function. Here is my code
#include<stdio.h>
#include<string.h>
#include<stdlib.h>
int main()
{
char *a1=(char*)malloc(100);
strcpy(a1,"Vivek");
char *b1=(char*)malloc(100);
strcpy(b1,"Ratnavel");
int i;
int len=strlen(a1);
for(i=0;i<strlen(b1);i++)
{
a1[i+len]=b1[i];
}
a1[i+len]='\0';
printf("\n\n A: %s",a1);
return 0;
}
I made corrections to the code. This is working. Now can I do it without strcpy?
Old answer below
You can initialize a string with strcpy, like in your code, or directly when declaring the char array.
char a1[100] = "Vivek";
Other than that, you can do it char-by-char
a1[0] = 'V';
a1[1] = 'i';
// ...
a1[4] = 'k';
a1[5] = '\0';
Or you can write a few lines of code that replace strcpy and make them a function or use directly in your main function.
Old answer
You have
0 1 2 3 4 5 6 7 8 9 ...
a1 [V|i|v|e|k|0|_|_|_|_|_|_|_|_|_|_|_|_|_|_|_|_]
b1 [R|a|t|n|a|v|e|l|0|_|_|_|_|_|_|_|_|_|_|_|_|_]
and you want
0 1 2 3 4 5 6 7 8 9 ...
a1 [V|i|v|e|k|R|a|t|n|a|v|e|l|0|_|_|_|_|_|_|_|_]
so ...
a1[5] = 'R';
a1[6] = 'a';
// ...
a1[12] = 'l';
a1[13] = '\0';
but with loops and stuff, right? :D
Try this (remember to add missing bits)
for (aindex = 5; aindex < 14; aindex++) {
a1[aindex] = b1[aindex - 5];
}
Now think about the 5 and 14 in the loop above.
What can you replace them with? When you answer this, you have solved the programming problem you have :)
char a1[] = "Vivek";
Will create a char array a1 of size 6. You are trying to stuff it with more characters than it can hold.
If you want to be able to accommodate concatenation "Vivek" and "Ratnavel" you need to have a char array of size atleast 14 (5 + 8 + 1).
In your modified program you are doing:
char *a1=(char*)malloc(100); // 1
a1 = "Vivek"; // 2
1: Will allocate a memory chunk of size 100 bytes, makes a1 point to it.
2: Will make a1 point to the string literal "Vivek". This string literal cannot be modified.
To fix this use strcpy to copy the string into the allocated memory:
char *a1=(char*)malloc(100);
strcpy(a1,"Vivek");
Also the for loop condition i<strlen(b1)-1 will not copy last character from the string, change it to i<strlen(b1)
And
a1[i]='\0';
should be
a1[i + len]='\0';
as the new length of a1 is i+len and you need to have the NUL character at that index.
And don't forget to free your dynamically allocated memory once you are done using it.
You cannot safely write into those arrays, since you have not made sure that enough space is available. If you use malloc() to allocate space, you can't then overwrite the pointer by assigning to string literal. You need to use strcpy() to copy a string into the newly allocated buffers, in that case.
Also, the length of a string in C is computed by the strlen() function, not length() that you're using.
When concatenating, you need to terminate at the proper location, which your code doesn't seem to be doing.
Here's how I would re-implement strcat(), if needed for some reason:
char * my_strcat(char *out, const char *in)
{
char *anchor = out;
size_t olen;
if(out == NULL || in == NULL)
return NULL;
olen = strlen(out);
out += olen;
while(*out++ = *in++)
;
return anchor;
}
Note that this is just as bad as strcat() when it comes to buffer overruns, since it doesn't support limiting the space used in the output, it just assumes that there is enough space available.
Problems:
length isn't a function. strlen is, but you probably shouldn't call it in a loop - b1's length won't change on us, will it? Also, it returns a size_t, which may be the same size as int on your platform but will be unsigned. This can (but usually won't) cause errors, but you should do it right anyway.
a1 only has enough space for the first string, because the compiler doesn't know to allocate extra stack space for the rest of the string since. If you provide an explicit size, like [100], that should be enough for your purposes. If you need robust code that doesn't make assumptions about what is "enough", you should look into malloc and friends, though that may be a lesson for another day.
Your loop stops too early. i < b1_len (assuming you have a variable, b1_len, that was set to the length of b1 before the loop began) would be sufficient - strlen doesn't count the '\0' at the end.
But speaking of counting the '\0' at the end, a slightly more efficient implementation could use sizeof a1 - 1 instead of strlen(a1) in this case, since a1 (and b1) are declared as arrays, not pointers. It's your choice, but remember that sizeof won't work for pointers, so don't get them mixed up.
EDIT: New problems:
char *p = malloc(/*some*/); p = /* something */ is a problem. = with pointers doesn't copy contents, it copies the value, so you're throwing away the old pointer value you got from malloc. To copy the contents of a string into a char * (or a char [] for that matter) you'd need to use strcpy, strncpy, or (my preference) memcpy. (Or just a loop, but that's rather silly. Then again, it may be good practice if you're writing your own strcat.)
Unless you're using C++, I wouldn't cast the return value of malloc, but that's a religious war and we don't need one of those.
If you have strdup, use it. If you don't, here is a working implementation:
char *strdup(const char *c)
{
size_t l = strlen(c);
char *d = malloc(l + 1);
if(d) memcpy(d, c, l + 1);
return d;
}
It is one of the most useful functions not in the C standard library.
You can do it using strcpy() too ;)
char *a = (char *) malloc(100);
char *b = (char *) malloc(100);
strcpy(a, "abc"); // initializes a
strcpy(b, "def"); // and b
strcpy((a + strlen(a)), b); // copy b at end of a
printf("%s\n",a); // will produce: "abcdef"
i think this is an easy one.
#include<stdio.h>
int xstrlen(char *);
void xstrcat(char *,char *,int);
void main()
{
char source[]="Sarker";
char target[30]="Maruf";
int j=xstrlen(target);
xstrcat(target,source,j);
printf("Source String: %s\nTarget String: %s",source,target);
}
int xstrlen(char *s)
{
int len=0;
while(*s!='\0')
{
len++;
s++;
}
return len;
}
void xstrcat(char *t,char *s,int j)
{
while(*t!='\0')
{
*t=*t;
t++;
}
while(*s!='\0')
{
*t=*s;
s++;
t++;
}
}
It is better to factor out your strcat logic to a separate function. If you make use of pointer arithmetic, you don't need the strlen function:
#include <stdio.h>
#include <stdlib.h>
#include <string.h> /* To completely get rid of this,
implement your our strcpy as well */
static void
my_strcat (char* dest, char* src)
{
while (*dest) ++dest;
while (*src) *(dest++) = *(src++);
*dest = 0;
}
int
main()
{
char* a1 = malloc(100);
char* b1 = malloc(100);
strcpy (a1, "Vivek");
strcpy (b1, " Ratnavel");
my_strcat (a1, b1);
printf ("%s\n", a1); /* => Vivek Ratnavel */
free (a1);
free (b1);
return 0;
}

Resources