Static array and dynamic array - c

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!

Related

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!

Function that prints reverse of a string/char array in C

I am rather new to the C language right now and I am trying some practice on my own to help me understand how C works. The only other language I know proficiently is Java. Here is my code below:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
const char * reverse(char word[]);
const char * reverse(char word[]) {
char reverse[sizeof(word)];
int i, j;
for (i = sizeof(word - 1); i <= 0; i--) {
for (j = 0; j > sizeof(word - 1); j++) {
reverse[i] = word[j];
}
}
return reverse;
}
int main() {
char word[100];
printf("Enter a word: ");
scanf("%s", word);
printf("%s backwards is %s\n", word, reverse(word));
return 0;
}
When the user enters a word, the program successfully prints it out when i store it but when i call the reverse function I made it doesnt return anything. It says on my editor the address of the memory stack is being returned instead and not the string of the array I am trying to create the reverse of in my function. Can anyone offer an explanation please :(
sizeof(word) is incorrect. When the word array is passed to a function, it is passed as a pointer to the first char, so you are taking the size of the pointer (presumably 4 or 8, on 32- or 64-bit machines). Confirm by printing out the size. You need to use strlen to get the length of a string.
There are other problems with the code. For instance, you shouldn't need a nested loop to reverse a string. And sizeof(word-1) is even worse than sizeof(word). And a loop that does i-- but compares i<=0 is doomed: i will just keep getting more negative.
There are multiple problems with your reverse function. C is very different from Java. It is a lot simpler and has less features.
Sizes of arrays and strings don't propagate through parameters like you think. Your sizeof will return wrong values.
reverse is an identifier that is used twice (as function name and local variable).
You cannot return variables that are allocated on stack, because this part of stack might be destroyed after the function call returns.
You don't need two nested loops to reverse a string and the logic is also wrong.
What you probably look for is the function strlen that is available in header string.h. It will tell you the length of a string. If you want to solve it your way, you will need to know how to allocate memory for a string (and how to free it).
If you want a function that reverses strings, you can operate directly on the parameter word. It is already allocated outside the reverse function, so it will not vanish.
If you just want to output the string backwards without really reversing it, you can also output char after char from the end of the string to start by iterating from strlen(word) - 1 to 0.
Edit: Changed my reverse() function to avoid pointer arithmetic and to allow reuse of word.
Don't return const values from a function; the return value cannot be assigned to, so const doesn't make sense. Caveat: due to differences between the C and C++ type system, you should return strings as const char * if you want the code to also compile as C++.
Arrays passed as params always "decay" to a pointer.
You can't return a function-local variable, unless you allocate it on the heap using malloc(). So we need to create it in main() and pass it as a param.
Since the args are pointers, with no size info, we need to tell the function the size of the array/string: sizeof won't work.
To be a valid C string, a pointer to or array of char must end with the string termination character \0.
Must put maximum length in scanf format specifier (%99s instead of plain %s — leave one space for the string termination character \0), otherwise vulnerable to buffer overflow.
#include <stdio.h> // size_t, scanf(), printf()
#include <string.h> // strlen()
// 1. // 2. // 3. // 4.
char *reverse(char *word, char *reversed_word, size_t size);
char *reverse(char *word, char *reversed_word, size_t size)
{
size_t index = 0;
reversed_word[size] = '\0'; // 5.
while (size-- > index) {
const char temp = word[index];
reversed_word[index++] = word[size];
reversed_word[size] = temp;
}
return reversed_word;
}
int main() {
char word[100];
size_t size = 0;
printf("Enter a word: ");
scanf("%99s", word); // 6.
size = strlen(word);
printf("%s backwards is %s\n", word, reverse(word, word, size));
return 0;
}

puts function gives garbage value in C

I want to copy one string to another string using pointer and I am getting garbage value (some unknown character) from printf function. What is wrong with it?
output is "string for copy**". At the place of ** getting some unknown character.
#include <stdio.h>
#include <conio.h>
void main()
{
char *s="string for copy",*c,*temp;//temp is used to back the
//pointer on 1st position
clrscr();
while(*s!=NULL)
{
*c=*s
c++;
s++;
}
c='\0';
c=temp;//back pointer to first position
printf("String from c:);
puts(c);
getch();
}
You need to allocate memory for your char * variables.
Also you never assign a value to temp (or allocate space for it) but then later in your code you assign c = temp. This means wherever c is currently at in memory will get assigned whatever was in memory at the location of temp.
c is char * are not allocating memory to it. So referring to it - reading from it or writing to it - is undefined behavior.
Allocate appropriate memory for c by using malloc() or other function before you copy characters into it.
So problem is not actually when you try to print using puts() but also when you copy characters to it by *c = *s.
Other than malloc(), change you code as below
...
//allocate memory for c
temp = c;
while(*s!='\0')
{
*c=*s
c++;
s++;
}
*c='\0'; //use *c
c=temp;
...

Delete chars from string C

So i start learning C from a book, and one of the exercises was to create a function that will take 2 string and delete from the first string the characters in the second string.
We stile didn't learn about pointer, so i guess this is possible without them,
but when i try to run my code its crush.
The code:
#include <stdio.h>
#include <string.h>
char squis(char string[], char sub[])
{
int i, c;
char ret_string[strlen(string)];
int map[strlen(string)];
for(i=0; i<= strlen(string);i++)
map[i] = -1;
for(i=0; i<= strlen(sub);i++)
{
while(string[c]!='\0')
{
if (string[c]==sub[i])
map[c] = c;
c++;
}
c=0;
}
for(i=0; i<= strlen(string);i++)
{
if (map[i]==-1)
ret_string[c++] = string[i];
}
ret_string[c] ='\0';
return ret_string[0];
}
int main()
{
char string[] = "string";
char remove[] = "sasas";
printf("%s",squis(string,remove));
return 0;
}
I stile newbie in C, so I think the problem lay on my lack of understanding in the way that C work.
Thanks a lot for help :-)
Update: its seem the problem laying in the return in the end of the function.
The function seems to work well when when i print ret_string inside the function(except one bug that make the function ignore the first char in the sub string, but i will deal with it later), but when i try to return the array to print it in the main function its fail.
There is specific rules for returning array in C?
Here is an obvious problem:
int map[strlen(string)];
for(i=0; i<= strlen(string);i++)
map[i] = -1;
You create an array of strlen(string) characters, and then you initialize strlen(string) + 1 characters in the array. Writing out of bounds of an array leads to undefined behavior, where anything could happen.
Change the loop condition to less-than <. You should probably do it in all your loops.
You have a similar problem with ret_string, which will be the string you return. It's going to be at most strlen(string) characters, but then you need to add one character for the string terminator so the array needs to be strlen(string) + 1 long.
Then you have the problem that the squis function only return a single character but in your printf call you treat this single character as a string. This should make your compiler scream a warning at you. If you fix this by simply returning ret_string you will have another case of undefined behavior, as you then return a pointer to a local variable, which goes out of scope when the function exits, so the returned pointer is no longer valid. And if you decide to allocate ret_string on the heap, with the current call you have a memory leak as then the pointer is not saved so you can free the allocated memory.

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

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++;
}

Resources