Array filling itself with only the last user entered inputed string - c

I m trying to make a piece of code that prompts the user for a number of string, n, dynamically allocates an array of n strings, and then prompts the user to enter n strings.
The problem I am having is the array is only showing itself being filled with the last string the user entered.
Example:
Program prompts user for n
User enters 3.
User enters "test1" for the first element in the array
User enters "test2" for the second element in the array
User enters "test3" for the third element in the array
I go to print the contents of the array, and it says each element is "test3"
Here is the code:
(flush_buffer() and strip_newline() are functions I wrote that are unimportant to the problem I am having)
printf("How many strings?\n");
scanf("%d", &max_strings);
flush_buffer();
string_array = (char**) malloc(max_strings * sizeof(char*));
for(i = 0; i < max_strings; i++)
{
scanf("%s", temp);
strip_newline(temp);
string_array[i] = temp;
printf("string_array[%d] is: %s\n", i, string_array[i]);
}
for(i = 0; i < max_strings; i++)
{
printf("i: %d\n", i);
printf("string_array[%d] is: %s\n", i, string_array[i]);
}
Any ideas on what I am missing here?

With the assignment
string_array[i] = temp;
you make all pointers in string_array point to the same place.
I suggest you use strdup to duplicate the string instead:
string_array[i] = strdup(temp);
Of course, this means you have to free all strings in the collection.

When you assign the strings:
string_array[i] = temp;
you just store a pointer of the temporary buffer in each string, which will be overwritten after the next string is read. In other words, all of your strings have the same value, namely temp, which has the contents of the last string read.
If you want to store your strings, you must allocate memory for string_array[i] and then copy the contents with strcpy. Alternatively, you can use a shortcut:
string_array[i] = strdup(temp);
Note that strdup allocates memory internally that you must free() at some point.

you can use this code:
int max_strings;
printf("How many strings?\n");
scanf("%d", &max_strings);
//allocate memory
char **string_array = (char**) malloc(max_strings * sizeof(char*));
for (int i = 0; i < max_strings; i++)
{
string_array[i] = (char*)malloc(sizeof(char) * 50);
}
for(int i = 0; i < max_strings; i++)
{
scanf("%s", string_array[i]);
printf("string_array[%d] is: %s\n", i, string_array[i]);
}
for(int i = 0; i < max_strings; i++)
{
printf("i: %d\n", i);
printf("string_array[%d] is: %s\n", i, string_array[i]);
}
//free memory
for (int i = 0; i < max_strings; i++)
{
free(string_array[i]);
}
free(string_array);

Related

Loop of sprintf only outputing final looped value

I have an char* array. I loop through the correct index of the array to put numbers.
However, it seems that the value placed in the index is wrong. It seems to only store the last call to sprintf.
For instance, if I want the numbers 0, 1, 2, 3. However, it seems to return 3, 3, 3, 3.
I have placed a printf statement to see if there is an error, but it produces the correct numbers. I assume there must be a weird error when using sprintf with an array.
char* printArray[12];
for (int i = 1; i < 12+1; i++) {
char *printVal;
char temp[10];
sprintf(temp, "%d", i-1);
printVal = temp;
printf("%s\n", printVal);
printArray[i-1] = printVal;
}
for (int i = 0; i < 12; i++) {
printf("%s\n", printArray[i]);
}
This is a simplified version. This produces the error.
I have attempted to use strcpy but that results in the same error.
The problem is that the memory for temp goes away when you leave each iteration of the for loop, so you can't save pointers to temp into printArray.
You need to make a dynamic copy of temp so you can save it outside the loop.
printArray should be an array of strings, not pointers, then you can use strcpy() to copy them.
char *printArray[12];
for (int i = 1; i < 12+1; i++) {
char temp[10];
sprintf(temp, "%d", i-1);
printf("%s\n", temp);
printArray[i-1] = strdup(temp);
}
for (int i = 0; i < 12; i++) {
printf("%s\n", printArray[i]);
}
If you don't have strdup() available, it's simple:
char *my_strdup(const char *s) {
char *new = malloc(strlen(s)+1);
if (new) {
strcpy(new, s);
}
return new;
}
Undefined behavior (UB)
printArray[i-1] = printVal; repeatedly assigns the address of local object char temp[10];.
Later code attempts to print the data in this common, now invalid, address: result UB.
Instead of copying a pointer, copy the contents into memory.
// char* printArray[12];
#define INT_STRING_SIZE 12
char printArray[12][INT_STRING_SIZE];
...
for (int i = 0; i < 12; i++) {
snprintf(printArray[i], sizeof printArray[i], "%d", i);
}
If code must remain as char* printArray[12];, allocate memory.
for (int i = 0; i < 12; i++) {
char temp[INT_STRING_SIZE];
int len = snprintf(temp, sizeof temp, "%d", i);
printArray[i] = malloc(len + 1);
// Check for allocation omitted brevity.
memcpy(printArray[i], temp, len + 1);
// or
strcpy(printArray[i], temp);
}
And free the memory when done.

How to create an array of strings of unknown size?

I'm trying to understand how can I create a C program that declares an "array of strings" whose size is unknown at the time of declaration. This is what I've got so far:
#include <stdio.h>
#include <stdlib.h>
int main(void) {
int n, i;
char** words;
printf("How many strings you want to input? \n");
scanf("%d", &n);
words = malloc(sizeof(char*) * n);
for (i = 0; i < n; i++) {
printf("Input your %d string: ", i + 1);
scanf("%s", words[i]);
}
for (i = 0; i < n; i++) {
printf("%s\n", words[i]);
}
return 0;
}
The program compiles, but I get a Segmentation fault error.
You only allocated memory for the pointer to the strings, but not for the strings themselves. Attempting to store strings at non-allocated memory invokes undefined behavior.
The pointer are just pointer. You cannot store strings in them. You need to reserve memory for where the pointer should point to.
#define STR_SIZE 100 // max length of a string (incl. null terminator)
printf("How many strings you want to input? \n");
if (scanf("%d", &n) != 1)
{
fputs("Error at input", stderr);
// further error routine.
}
// allocate memory for the pointer to the strings.
words = malloc(sizeof(*words) * n);
if (!words)
{
// error routine if the memory allocation failed.
perror("malloc");
exit(EXIT_FAILURE);
}
// allocate memory for the strings themselves.
for (int i = 0; i < n; i++)
{
words[i] = malloc(sizeof(**words) * STR_SIZE);
if (!words[i])
{
// error routine if the memory allocation failed.
perror("malloc");
exit(EXIT_FAILURE);
}
}
Side notes:
Always check the return of memory-management functions if an error happened at the allocation! Same goes for input operations such as scanf().
Note that using sizeof(*words) and sizeof(**words) instead of sizeof(char*) and sizeof(char) is more safe for the case your code changes.
You did not allocate the memory properly for individual char pointer words[i].
This was ok - you allocated memory for the pointer to pointer to char words:
words = malloc(sizeof(char*) * n);
But then you haven't allocated for individual pointers of that words yet. To do so, you need to provision how much buffer to for individual word. As an example, if each word is 100 char, then:
for (i = 0; i < n; i++)
{
printf("Input your %d string: ", i + 1);
words[i] = malloc(sizeof(char) * 100); //<--
scanf("%s", words[i]);
}
Also remember to free the buffer once you're done.
for (int i=0; i<n; ++i) {
free(words[i]);
}
free(words);
return 0;

questions regarding tokenisation in c

I am writing a tokenisation program. I want to get input from a file, then store it in an input pointer. I am using the strtok function but when I print my tokens[i] I get NULL.
int tokenise(char *input, int file_output)
{
int i = 0;
char *tokens[100];
for(i=0 ;i<=20;i++)
{
tokens[i]= (char*)malloc(sizeof(char*));
}
char delim[] = " ,.;#/";
printf("\n ------------- buffer data is %s",input);
tokens[i] = strtok(input , delim);
printf("tokens are %s",*tokens[0]);
int j=0;
while(NULL != tokens[i])
{
i++;
tokens[i] = strtok(NULL,delim);
}
for(j = i; j <= 0; j--)
{
write(file_output,tokens[i],strlen(tokens[i]));
}
for(i = 0; i <= 20; i++)
{
printf("%s \n",*tokens[i]);
}
return SUCCESS;
}
For some reason you allocate memory and write pointers to the first 21 elements of tokens[]. At the end of that loop, i is 21. You then parse the input string using strtok(), storing its results in continuing array elements, from tokens[21]. So two of your loops need rewriting:
for(j=21; j<i; j++)
write(file_output,tokens[j],strlen(tokens[j]));
for(j=21; j<i; j++)
printf("%s \n",*tokens[j]);
But it would be better if you removed the first loop that allocates unnecessary memory. strtok() returns pointers to the original string, which it breaks into pieces by inserting '\0' terminators, so you only need to store the pointers in the array tokens[].

dynamically allocated char array only prints first character from each index

I'm trying to read from a file which has words in which are separated by spaces, the words are read within a loop. They are read correctly within the loop and they can be printed as so but as soon as the loop ends I am only able to print the first character of each element. Here is the code:
char **storeWords(char **words){
char* fileName = "words.txt";
FILE* fp = fopen(fileName, "r");
int i;
for (i = 0; i < 2; i++){
int j;
for (j = 0; j < 20; j++){
fscanf(fp, "%s", &words[i][j]);
printf("%s", &words[i][j]); //prints correctly
}
}
printf("%s", &words[0][0]); //prints first character of selected element
fclose(fp);
return **words;
}
int main(){
char **words = (char**)malloc(6 * sizeof(char*));
for (int i = 0; i < 6; i++){
words[i] = (char*)malloc(20 * sizeof(char));
}
storeWords(words);
system("pause");
return 0;
}
I don't understand why this happens, it would be appreciated if this could be explained. Thanks.
The problem is that you are allocating a 2D array of chars, not a 2D array of strings.
This is a pointer to a string, or a 1D array of chars:
char*
This is a pointer to a 1D array of strings, or a 2D array of chars:
char**
And this is a pointer to a 2D array of strings, or a 3D array of chars:
char***
You were trying to store a string to a char, and the only reason you didn't get a crash was because you allocated a [6][20] array but only iterated over 2x20 words, so there was room for overflow.
So, in your main function you need to allocate like this (note you don't need to cast the pointer returned from malloc):
char ***words = malloc(6 * sizeof(char**));
for (int i = 0; i < 6; i++){
words[i] = malloc(20 * sizeof(char*));
}
Change your function declaration to use the new type:
char ***storeWords(char ***words)
Then when you read in the words, use a temp char buffer and dynamically allocate enough space based on the word size:
for (j = 0; j < 20; j++){
char word[100]; // max word size of 100 chars
fscanf(fp, "%99s", word);
words[i][j] = malloc(strlen(word) + 1);
strcpy(words[i][j], word);
printf("%s", words[i][j]); //prints correctly
}
Note that when you print out a word you don't need to use the ampersand, because words[i][j] now contains a char* not a char:
printf("%s", words[0][0]);

fgets "Access violation writing location 0xCCCCCCCC." error

Error: Unhandled exception at 0x60092A8D (msvcr110d.dll) in C_Son60.exe: 0xC0000005: Access violation writing location 0xCCCCCCCC.
When below code executed this error code is given.(Compiles successfully)
Where is my mistake?
#include <stdio.h>
int i;
int main(void){
char *names[3];
//get the names of the cities
puts("Enter names of cities");
for (i = 0; i < 3; i++)
{
fgets( names[i], 99, stdin);
}
//print entered names
for (i = 0; i < 3; i++)
{
printf("%s", *names[i]);
}
getch();
}
You need to allocate memory to which the char pointers point to before you read them in
for instance:
for (i = 0; i < 3; i++)
{
names[i] = malloc(200);
fgets( names[i], 99, stdin);
}
2 things:
you need to allocate the strings you created- you can do it with malloc(100 * sizeof(char))
when printing you do *names[i] which means - **(names + i).
all you need is names[i]
use the code:
#include <stdio.h>
int i;
int main(void){
char *names[3];
//get the names of the cities
puts("Enter names of cities");
for (i = 0; i < 3; i++)
{
names[i] = (char *)malloc(100 * sizeof(char));
fgets( names[i], 99, stdin);
}
//print entered names
for (i = 0; i < 3; i++)
{
printf("%s", names[i]);
}
getch();
}
You must allocate your memory before storing anything into it. When you need to allocate an array of elements, and you do not know the number of elements at compile time, you must use malloc() to allocate them.
Don't forget to free your dynamically allocated memory later in order to avoid memory leaks!

Resources