I'm attempting to convert an array of ints to an array of strings in c. My code so far is:
int args[] = {1, 3000};
char *str_args[15];
int i = 0;
for(i; i<=((sizeof(args)/sizeof(args[0]))); i++){
char buffer[10];
sprintf(buffer, "%d", args[i]);
str_args[i] = buffer;
}
printf("%s\n", *str_args[0]);
This code causes my program to crash instead of outputting 1 (the first arg) like I expect. What am I missing here? Thanks in advance
It's because you assign each entry of str_args to a local pointer, one that goes out of scope once the loop loops.
You might want to consider strdup:
str_args[i] = strdup(buffer);
Of course, you then have to free the memory allocated by strdup.
You also have a problem when printing just after the loop, when you want to print a string, but *str_args[0] dereferences the first string. i.e. it's the first character and not a string. Remove the dereferencing operator * and it should work just fine.
On the printf, the datatype of the parameter is incorrect
Also you need to copy temporary "buffer" to allocated memory or each loop overwrites the next
Code below fixes these two problems
#include<stdio.h>
#include<string.h>
main() {
int args[] = {1, 3000};
char *str_args[15];
int i = 0;
for(i; i<=((sizeof(args)/sizeof(args[0]))); i++){
char buffer[10];
sprintf(buffer, "%d", args[i]);
str_args[i] = strdup(buffer);
}
printf("%s\n", str_args[0]);
}
for(i; i<=((sizeof(args)/sizeof(args[0]))); i++){
should be :
for(i=0; i<((sizeof(args)/sizeof(args[0]))); i++){//take out the `=` after >, add i=0 first.
As the way it is originally written, i will reach 2, and cause the overrun you experienced.
(i=0 is optional since you have i initialized in the line before, but its better form to just do it in the for loop.)
You are overrunning your buffers otherwise. BTW, you do realize that there are only two items in the following array, right?
int args[] = {1, 3000};
Related
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!
I got an assignment from my teacher to write a code that compares a given word to a bunch of words located in an array of strings.
If the word in the array is lexicography smaller than the word given, I need to put it inside a new array.
else, I'm moving to the next word.
for example;
given word: hello
arr=bus, alpha, world, java.
new array=bus,alpha.
I wrote a code that does that using STRCMP, but the computer throws me out when it gets to the strcpy part.
this is my code
char** LowerSTR(char* arr[], int size_arr, char* str, int* size_res)
size_res = 0;
char** newArr= (char**)calloc(size_arr, sizeof(char));
for (int i = 0; i < size_arr; i++)
{
if (strcmp(str, arr[i])==1)
{
for (int k = 0; k <size_arr;k++)
{
strcpy(newArr[k], arr[i]);
}
size_res++;
}
}
if (size_res == 0)
return NULL;
else return newArr;}
maybe I should use STRCAT instead?
please help :\
In calling strcpy with newArr[k] as an argument you're dereferencing a NULL pointer.
Recall that we allocate newArr as follows:
char** newArr= (char**)calloc(size_arr, sizeof(char));
There's actually multiple errors here. The first is that we calloc with sizeof(char) when we in fact want a region of char*s. So corrected1
we have
char** newArr= calloc(size_arr, sizeof(char*));
As we've calloc'd this piece of memory, all of it is zeroed. Thus when strcpy internally accesses newArr[k] (itself of type char*) it points to memory address 0, which is likely reversed by the OS, and in any case, not a valid address in the context of our program.
In order to resolve this, we need to allocate for each string. For instance, one might do
newArr[k] = malloc(strlen(arr[i]) + 1); // The +1 is for the \0 termination character
the line before we strcpy.
You also have a bug with size_res as you just treat it as an int instead of an int* as you need to dereference it when you want to change or read the value to which it points.
1 See here for why I've removed the cast.
You should scan newArr and print all strings inside, something like:
for (int i = 0; i < *size_res; i++) // !
{
printf("%s\n",newArr[i]);
}
(!) 'size_res' is passed to the function as a pointer to int,
I have a three row input file.
First row is an int, the second row is ints with space, the third row is a string.
I have to scan them than manipulate the string based on the ints.
My problem is that I can scan the ints, but scanning the string causes segmentation fault at fclose.
My code:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int main()
{
FILE* in = fopen("be.txt", "r");
FILE* out = fopen("ki.txt", "w");
if(in==NULL){
printf("Error opening in!\n");
return -1;
}
if(out==NULL){
printf("Error opening out!\n");
return -1;
}
int brknglength, i;
fscanf(in, "%d", &brknglength);
printf("%d\n", brknglength);
int* seed[brknglength];
seed[brknglength] = malloc(sizeof(int[brknglength]));
for(i = 0; i < brknglength; i++){
if (fscanf(in, "%d", &seed[i]) != 1) {
printf("%d", i);
}
printf("%d.: %d \n", i, seed[i]);
}
char string;
fscanf(in, "%s", &string);
free(seed[brknglength]);
fclose(in);
fclose(out);
return 0;
}
What causes the segmentation fault?
Your first Problem appears here:
int* seed[brknglength];
This defines an array of int pointers on the stack.
seed[brknglength] = malloc(sizeof(int[brknglength]));
This initializes the element behind the array and overwrites your stack.
To fix it, use either:
int seed[brknglength]; /* use without free(seed) */
or:
int *seed = malloc(sizeof(int[brknglength]));
/* ... */
free(seed);
The latter also works for compilers, which do not support variable length arrays.
Your second problem is reading a string into a single char variable, which also overwrites the stack. Try something like:
char string[100];
fscanf(in, "%99s", &string);
Be aware, that "%s" stops at whitespace. Use something like "%99[^\t\n]" to define your own separators, or "%99c" for a fixed length string.
The GNU Compiler offers the modifier "m" (=allocate memory) as a convenient non-standard extension for all these cases:
char *string;
fscanf(in, "%ms", &string);
/* ... */
free(string);
int* seed[brknglength];
seed[brknglength] = malloc(sizeof(int[brknglength]));
It looks like what you tried to do here is make seed a pointer to an array of int and allocate space for it. However, that is the wrong syntax. Because [ ] has higher precedence than *, int* seed[brknglength]; defines an array of pointers to int. Also, the name of the object is seed, not seed[brknglength], so you would assign a value to it with seed = …, not with seed[brknglength] = ….
To make a pointer to an array and allocate space for it, use:
int (*seed)[brknglength];
seed = malloc(sizeof *seed);
Those can be combined (which is not a violation of the above note about using seed = for assignment—initialization has a special syntax):
int (*seed)[brknglength] = malloc(sizeof *seed);
However, you probably do not want that. If size is a pointer to an array, then you have to use *seed wherever you want to refer to the array. So fscanf(in, "%d", &seed[i]) would have to be fscanf(in, "%d", &(*seed)[i]).
Instead of making seed a pointer to an array, just make it a pointer to an int, and allocate space for as many int as you want:
int *seed = malloc(brknglength * sizeof *seed);
Then you can use seed[i] for element i of the array instead of having to use (*seed)[i].
char string;
That defines string to be a single char. But fscanf(in, "%s", &string); reads as many characters as the input has until a white-space character. So you need to pass fscanf a pointer to the first of many char. You can either declare string to be an array:
char string[100];
or a pointer to space that is allocated:
char *string = malloc(100 * sizeof *string);
Then you can use fscanf(in, "%s", string);. Note that you do not want to pass &string. That is the address of the array or of the pointer, depending on how you defined string. You want to pass the address of the first character, which is &string[0], or, equivalently, string. (If string is an array, it is automatically converted in this expression to a pointer to its first element, so it is equivalent to &string[0].)
Note that fscanf will read as many character as the input contains until a white-space character appears. That can exceed whatever size you provide for string. So you need to ensure the input does not have too many characters or tell fscanf to limit how much it reads, which you can do with:
fscanf(in, "%99s", string);
or:
int n = 99;
fscanf(in, "%*s", n, string);
Note that fscanf should be told to read at most one character less than the space in string because it needs to add a terminating null character.
To free these objects, use:
free(seed);
free(string); // (If defined as a pointer, not an array.)
I need to read an array of n strings from 2 letters in each (e.g. n = 3, need to read something near "ab bf cs"). I use this code and get segmentation fault:
int n;
scanf("%d", &n);
char array[n][2];
char *tmp;
for (int i = 0; i < n; i++)
{
scanf("%s", &tmp);
strcpy(array[i], tmp);
}
Please help me to fix it!
Problem 1
To store a string of length 2, you need a char array of size 3. Use:
char array[n][3];
Problem 2
You are using &tmp in the call to scanf. That is wrong on two accounts.
The type is not appropriate. Type of &tmp is char**. scanf needs a char* with the %s format specifier.
&tmp cannot hold a string.
You could use
scanf("%s", tmp);
That will be OK from type point of view but it won't ok from run time point of view since tmp does not point to anything valid.
You can do away with tmp altogether and use:
scanf("%s", array[i]);
That entire block of code can be:
int n;
scanf("%d", &n);
char array[n][3];
for (int i = 0; i < n; i++)
{
// Make sure you don't read more than 2 chars.
scanf("%2s", array[i]);
}
There are a couple things you need to fix here.
Remember that one "string" (char[]) always ends with a null terminating character \0. So, whenever you create a char[], you must leave enough space for that. For example:
char str[3] = "foo"; looks like ['f', 'o', 'o'], but
char str[4] = "foo"; looks like ['f', 'o', 'o', '\0'].
Unexpected consequences can occur when using the former.
This means that you should change char array[n][2] to char array[n][3].
Remember that pointers are different than arrays. If you want to use a pointer, you must allocate memory for it, otherwise you will most likely seg fault.
In your program, it's simple enough that you can probably get away with not using a pointer, especially since you know the the length of each string that you will be storing (2).
You could change char *tmp to char tmp[3].
You can actually refactor your code so you don't need the tmp variable at all. If you want, you can just store the word you read into the array directly. For example:
scanf("%s", array[n]);
If you are really insistent on using that tmp variable as a char *, then allocate memory for it, like so:
char *tmp = (char*)malloc(3 * sizeof(char));
As a sidenote, if you are adhering to the ISO C90 standards, you shouldn't intermix variable declarations in code, so in your loop where you have for(int i = 0...), you should declare int i; at the top of the file, and then assign it in the loop for(i = 0...).
First, as user3121023 pointed out in the comments, char *tmp; creates a pointer without memory allocated to it. scanf() needs an array, and you need space for the terminating '\0' (which is probably the source of your segmentation fault). So you could try scanf("%s", array[i]);.
Second, it's a good idea to use "%2s" instead of "%s" so the user doesn't input 3 digits and overflow your buffer.
Here's one solution.
int n;
scanf("%d", &n);
char array[n][3];
for (int i = 0; i < n; i++)
{
scanf("%2s", array[i]);
}
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!