I am trying to store words from a text file in dynamically assigned arrays of chars. I am using pointer arrays to array of chars in order to allocate memory dynamically but for some reason it only stores the last input word to all the arrays of chars I am pointing to, even though in some places that strings should not fit as I allocated space for smaller strings.
Here is the code:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int main () {
char input_string[30];
int string_length, text_length;
// Calculating number of words in text file.
text_length=0;
freopen("in.txt", "r", stdin);
while (scanf("%s", &input_string)!=EOF) {
text_length++;
}
freopen("CON", "r", stdin);
// Dynamically assigning array of chars to store words
char **pointer;
int i;
pointer=(char*)calloc(text_length, sizeof(char));
freopen("in.txt", "r", stdin);
for (i=0;i<text_length;++i) {
scanf("%s", &input_string);
string_length = strlen(input_string);
pointer[i]=(char*)calloc(string_length, sizeof(char));
*(pointer+i)=input_string;
}
for (i=0;i<text_length;++i) {
printf("%s ", *(pointer+i));
}
freopen("CON", "r", stdin);
return 0;
}
*(pointer+i)=input_string
Here input_string is the array and it takes the string from the file. So in the above statement, you are overwriting address of pointer array(allocated memory) with the input string.
pointer[i]=(char*)calloc(string_length, sizeof(char)); // alloacted memory
*(pointer+i)=input_string; //alloacted memory overwritten here pointer[i] and *(pointer+i) both both notifies same
So each index of the array has the same base address of input_string and while de-refer it will give the string which is present in the array(last string). This is the reason for your problem. Better you do memcpy or strcpy.
pointer[i]=(char*)calloc(string_length, sizeof(char));
strcpy(pointer[i], input_string)
or
pointer[i]=(char*)calloc(string_length, sizeof(char));
memcpy(pointer[i], input_string, string_length));
((pointer+i)+string_length)='\0'; /* assigning null character at end of string * /
Related
I want to have an array of strings and the user to enter a string at a time. The program should either end if the the array is full or when the user skips an input (so the string would be equal to "\n".
Problem is that I have to dynamically allocate memory for each of these strings and I cant find a way to do that efficiently.
Excuse my English on this one but the array should be an array of pointers to char (for example char *pin[MAX])
This is my code:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define MAX 5
int main()
{
char *pin[MAX];
char s[] = "";
int n = 0;
while(s != "\n"){
printf("Enter a string: ");
gets(s);
pin[n] = malloc(sizeof(char)*strlen(s));
strcpy(pin[n], s);
n++;
if(n = MAX - 1) break;
}
for(int i = 0; i < MAX; i++){
printf("%s ", *pin[i]);
}
return 0;
}
Take input with fgets and store it in a temporary buffer (128 or 256 bytes large etc).
Call strlen on the read string stored in this buffer to see how much to allocate.
Allocate memory with malloc for pointer pin[n] and strcpy the string there.
NOTE:
char *s; ... while(s != is nonsense since s has not been initialized.
s != "\n" is nonsense since that's not how you compare strings in C.
pin[n] == &s; is nonsense because it's just random stuff typed out without the programmer knowing why. Programming by trial & error doesn't work.
In general you need to study arrays and pointers before strings.
I need to load the contents of a file into two string arrays. I tried the following and it is not working.
file.txt contains 10 records and each record has two string values separated by whitespace.
CODE:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int main(void) {
char line[12][20];
FILE *fptr = NULL;
int i = 0;
int tot = 0;
fptr = fopen("file.txt", "r");
char arr[20][20];
while (fgets(line, sizeof(line), fptr)) {
strcpy(arr[i],line);
i++;
}
tot=i;
for (int i=0; i<tot; i++) {
printf("first value %s",arr[i][0]);
printf("second value is %s",arr[i][1]);
printf("\n");
}
return 0;
}
If I understand correctly, you're trying to store data in a structure like:
{{"line1A", "line1B"}, {"line2A", "line2B"}, {"line3A", "line3B"}}
It looks like you need an array where each element consists of two arrays (strings), one for the first value and one for the second value on each line. If this is the case, you need a three dimensional array of chars.
In the example below I've declared arrayOfLines as array with 12 elements each of which has 2 arrays of chars (for your two values per line), with space for 20 chars in each string (NULL terminated char array)
There are some other problems with your code:
The first parameter for fgets() should be a char * - a pointer to a string buffer. Your code passes in a multi-dimensional array of chars.
Your while loop should continue until fgets returns NULL
You need to split each line into multiple strings
Check for buffer overruns when copying strings with strcpy()
In the example code I used strtok() delimited by a " " space character - you may need to play around with this - strtok can accept an array of chars to be used as a delimiter. In the example, I split the first string using the first space char, and the second string is delimited by the end of line.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int main(void)
{
// Array for 12 lines, each with 2 strings, each string max 20 chars
// Adjust values as required.
char arrayOfLines[12][2][20];
FILE *fptr = NULL;
int i = 0;
int tot = 0;
fptr = fopen("file.txt", "r");
// char arr[20][20]; not needed
char line[20];
while(fgets(line, sizeof(line) / sizeof(line[0]), fptr) != NULL)
{
// Rudimentary error checking - if the string has no newline
// there wasn't enough space in line
if (strchr(line, '\n') == NULL) {
printf("Line too long...");
return EXIT_FAILURE;
}
// Split string into tokens
// NB: Check for buffer overruns when copying strings
char *ptr1 = strtok(line, " ");
strcpy(arrayOfLines[i][0], ptr1);
char *ptr2 = strtok(NULL, "\n");
strcpy(arrayOfLines[i][1], ptr2);
i++;
}
tot=i; // Unecessary - just use a different variable in your loop and use i as the upper bound
for (int i=0;i<tot;i++)
{
printf("first value %s\n", arrayOfLines[i][0]);
printf("second value is %s\n", arrayOfLines[i][1]);
printf("\n");
}
return 0;
}
printf("first value %s",arr[i][0]);
printf("second value is %s",arr[i][1]);
Basicly all you are doing is printing 2 chars from i word when you want to print full string you should do it like this: printf("%s",arr[i]); You said that value is separated by whitespace so when you are getting line from file you will save it to arr[i] (if first line in file contains "Hello World", your arr[0] will contain "Hello World") when you want to split it into 2 printf you need to print them char by char until space.
Edit: I reminded myself about function sscanf you can use it to get data from file array like you whould do it with keyboard input
You can use this to do that
Code
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
int main(void){
char line[12][20];
char arr[20][20];
FILE *fptr=NULL;
int i=0;
fptr = fopen("file.txt", "r");
if(!fptr){
printf("cant open file\n");
exit(1);
}
while(fgets(*line, sizeof(line), fptr)){
strncpy(arr[i],*line, sizeof(*line));
i++;
}
for (int j=0;j<i;j++){
printf("%s\n", arr[j]);
}
return 0;
}
Notes and changes I made on your code:
Check fptr as return value of open() if it's NULL decide what to do.
Remove unnecessary tot variable and use another index j in last for loop.
Use strncpy() as a better version of strcpy()
Correct way of print arr, printf("%s\n", arr[j]);
\n can be embed on first printf()
So this course I'm doing wants us to play around with memory management and pointers. I'm not really fully understanding them.
I keep getting a error:
Segmentation fault (Core dumped)
Apparently I don't have access to memory?
It's something wrong in my slen function?
/*
In these exercises, you will need to write a series of C functions. Where possible, these functions should be reusable (not use global variables or fixed sized buffers) and robust (they should not behave badly under bad input eg empty, null pointers) .
As well as writing the functions themselves, you must write small programs to test those functions.
- Remember, in C, strings are sequences of characters stored in arrays AND the character sequence is delimited with '\0' (character value 0).
----------------------------------------------------
1) int slen(const char* str)
which returns the length of string str [slen must not call strlen - directly or indirectly]
*/
#include <stdio.h>
#include <stdlib.h>
/* Returns the length of a given string */
int slen(const char* str) {
int size = 0;
while(str[size] != '\0') {
size++;
}
return size;
}
/*
2) char* copystring(const char* str)
which returns a copy of the string str. [copystring must not call any variant of strcpy or strdup - directly or indirectly]*/
char* copystring(const char* str) {
int size = slen(str);
char *copy = (char*) malloc (sizeof(char) * (size + 1));
copy[size] = '\0';
printf("before loop");
int i = 0;
while (*str != '0') {
copy[i++] = *str++;
}
return copy;
}
int main() {
char *msg = NULL;
printf("Enter a string: ");
scanf("%s", &msg);
int size = slen(msg);
//printf("The length of this message is %d.", size);
// printf("Duplicate is %s.", copystring(msg));
// Reading from file
}
The problem isn't in your slen function, it happens before that when you're using scanf:
you need to make some space for the string that you're reading from the user using scanf
you don't need to pass the address of your memory buffer to scanf, the variable is already holding an address.
Amended code:
char msg[101];
printf("Enter a string: ");
scanf("%s", msg);
int size = slen(msg);
Alternately, if you're being asked to learn about memory allocation, study the usage of malloc:
char *msg = malloc(101);
printf("Enter a string: ");
scanf("%s", msg);
int size = slen(msg);
While learning about malloc, don't forget to also study up on the associated usage of free.
Also important and significant here is the management of your buffer size: when you make memory for the string that you'll be scanning from the user, you should put a limit on the amount of string that you actually read. There are a few ways to do this: start by studying the scanf format string, where you can use:
scanf("%100s", msg);
You need to assign memory to msg in your main
Either use char msg[10] or use malloc.
char *msg = malloc(10*sizeof(char))
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);
}
I'm try to get from the user 5 strings, and store that string into a array of char string, but, when I try to use the program, the output of the program is allways the same, the last value of user have inputed...
See my code:
#include <stdio.h>
int main()
{
int i = 0;
char *s[50];
char str[50];
for(i=0;i<5;i++)
{
fgets(str, 50, stdin);
s[i] = str;
}
for(i=0;i<5;i++)
printf("%s\n ", s[i]);
}
So, How I can solve this, how I can put the value digited by the user into array, and print the values in other time ???
You need to use strcpy instead of simple assignment.
str is a memory location, all s[i] = str is doing is pointing to the same buffer that is overwritten every time you call fgets.
Something like the following will get you what you need:
#include <stdio.h>
int main()
{
int i = 0;
char s[5][50];
char str[50];
for(i=0;i<5;i++)
{
fgets(str, 50, stdin);
strcpy(s[i],str);
}
for(i=0;i<5;i++)
printf("%s\n ", s[i]);
}
You're creating a single array of characters with the following line
char str[50];
And then every pointer in your array s is pointing to that same single memory location. Everytime you call fgets, you're overwriting the string that is stored in that memory, and as such when you print out each of the strings in the s array, you're getting the same thing: the last value the user entered, which is stored in that single locally allocated block of memory.
Try allocating a new block of memory for each string you read in from the user, and then storing the new memory block's pointer in s:
char *str;
for(i=0;i<5;i++)
{
str = malloc(50);
fgets(str,50,stdin);
s[i] = str;
}
All the pointers of s point to str. So only the last input is stored.
Do:
for(i=0;i<5;i++)
{
fgets(str, 50, stdin);
s[i] = strdup(str);
}
If strdup() is not available (POSIX function) then you can implement it or use malloc() + strcpy().
for(i=0;i<5;i++)
{
fgets(str, 50, stdin);
s[i] = malloc(strlen(str) + 1);
strcpy(s[i], str);
}
And finally free() the pointers in s:
for(i=0;i<5;i++)
{
free(s[i]);
}
Note that char *s[50] only declares 50 pointers (not pointers to 50 characters!); they need to point somewhere before you can copy something to them. What about a 2-dim array of char:
char s[5][50];
and then reading into them with
fgets (s[i], 50, stdin);
Advantage: No need to mess with strdup, malloc and free.