I'm new to C (coming from Java) and naturally that poses some difficulties. I would like to write just a short program that reads in char-Arrays from stdin and stores the individual strings in an array. After reading in the strings I just want to have them printed out, but that's when it gets really confusing for me.
Here's my code:
#include <stdlib.h>
#include <stdio.h>
int main(){
char **stringarray[2];
char buffer[5];
int i = 0;
while( i < 2 && fgets(buffer, 5, stdin) != NULL){
char *tmp = buffer;
stringarray[i] = &tmp;
i++;
}
for(int i = 0; i < 2; i++){
printf("%s\n", &stringarray[i]);
}
return 0;
}
The first part does in fact compiles (i.e. the part before the print out). I understand that my stringArray has to be an array of char pointers, because that's what a char array basically is in c. It's a pointer to the first character. At first I just wrote
while( i < 2 && fgets(buffer, 5, stdin) != NULL){
stringarray[i] = buffer;
i++;
}
which also compiled, but of course then I have one pointer that points to buffer, which will only save the last string that has been read.
What do I have to do that I can store a simple array of strings?
I suggest you change your code as following.
#include <stdlib.h>
#include <stdio.h>
#include <string.h> /* to use strdup function */
int main(){
char *stringarray[2]; /* I don't understand why you use pointer to pointer than pointer, char **stringarray[2]; */
char buffer[6]; /* I suggest 6 than 5, because string has terminate byte in C */
int i = 0;
while( i < 2 && fgets(buffer, 5, stdin) != NULL){
stringarray[i] = strndup(buffer, 5);
i++;
}
for(int i = 0; i < 2; i++){
printf("%s\n", stringarray[i]); /* changed stringarray */
}
return 0;
}
char **stringarray[2]; is like char ***stringarray because an array is like a pointer to the first value of the array.
printf wants a char* and &stringarray[i] is a char**
if a string is an array then an array of strings is an array of array.
So the code is :
int main()
{
char stringarray[2][5];//array of (array of char)
char buffer[5];
int i = 0;
while( i < 2 && fgets(buffer, 5, stdin) != NULL)
{
strcpy(stringarray[i],buffer); //copies the buffer into the string array
i++;
}
for(i = 0; i < 2; i++)
{
printf("%s\n", stringarray[i]);
}
return 0;
}
If you didn't want to use buffer you could just writte :
while( i < 2 && fgets(stringarray[i], 5, stdin) != NULL)
{
i++;
}
Note that you get 5 characters, the last one will be the NUL terminator \0. And because you have to press enter to validate, the one before \0 will be Line Feed\n. And you will only have 3 characters you really wanted.
You can do it using dynamic allocation technique as below .
#include<stdio.h>
#include<malloc.h>
#include <stdlib.h>
int main()
{
int num;
int len=0;
int i;
printf("Enter the number of elements to be entered ");
scanf("%d",&num);
//Allocate memory for the array of strings
char **var=(char **)malloc(num * sizeof(char *));
for(i=0;i<num;i++)
{
printf("Enter the string : ");
//get strings using getline
getline(&var[i],&len,stdin);
}
for(i=0;i<num;i++)
{
printf("String %d : %s \n",i,var[i]);
}
free(var);
}
Related
I want to receive the number of lines of input from the user then read and save the lines of unknown lengths in an array.
I know that the way I am saving the lines is wrong but I don't know how to correct it.
int nos; // number of strings
scanf_s("%d", &nos);
char** strs = malloc(nos * sizeof(char*)); // array of strings
for (int i = 0; i < nos; i++) // receiving strings
{
scanf_s("%s", (strs+i));
}
You're close, but you're forgetting to allocate memory for the string. If you're working with POSIX-compliant systems (i.e. pretty much everything except Windows) then use the %ms scanf() format specifier to allocate the buffer for the string as you're reading it (note that this stops after whitespace):
scanf("%ms", &strs[i]);
For Windows, implement a gets()-like function:
#include <stdlib.h>
#include <stdio.h>
int msgets(char **str)
{
int ch = 0;
size_t len = 0;
while(ch != '\n')
{
len++;
*str = realloc(*str, len);
ch = getchar();
(*str)[len-1] = ch;
}
(*str)[--len] = 0;
return len;
}
Here's how to use it in replacement of the scanf() line:
msgets(&strs[i]);
Other than that, your code looks fine.
Here's an almost complete example with my code included:
#include <stdlib.h>
#include <stdio.h>
int msgets(char **str)
{
int ch = 0;
size_t len = 0;
while(ch != '\n')
{
len++;
*str = realloc(*str, len);
ch = getchar();
(*str)[len-1] = ch;
}
(*str)[--len] = 0;
return len;
}
int main(void)
{
int nos; // number of strings
scanf("%d ", &nos);
char** strs = malloc(nos * sizeof(char*)); // array of strings
for (int i = 0; i < nos; i++) // receiving strings
{
msgets(&strs[i]);
}
/* Do something with strs[] here */
return 0;
}
if you read carefully this answerHow can I read an input string of unknown length? , and modify your code it should be something like this.
I also add a print for loop to see the results of this code
#include <stdio.h>
#include <stdlib.h>
char *inputString(FILE* fp, size_t size){
char *str=NULL;
int ch;
size_t len = 0;
str = realloc(str, sizeof(char)*size);
if(!str){
printf("[DEBUG]\n");
return str;
}
while(EOF!=(ch=fgetc(fp)) && ch != '\n'){
str[len++]=ch;
if(len==size){
str = realloc(str, sizeof(char)*(size+=16));
if(!str)return str;
}
}
str[len++]='\0';
return realloc(str, sizeof(char)*len);
}
void empty_stdin (void) /* simple helper-function to empty stdin */
{
char c;
while ((c = getchar()) != '\n' && c != EOF);
return;
}
int main(void){
int nos,i; /*number of strings*/
scanf("%d", &nos);
empty_stdin();
char ** strs = malloc(nos * sizeof(char*)); /*array of strings*/
for (i = 0; i < nos; i++) {/*receiving strings*/
*(strs+i) = inputString(stdin,1);
}
for(i=0;i<nos;i++){
printf("%s\n",*(strs+i));
}
return 0;
}
input:
3
123456789
foo
hello world
output:
123456789
foo
hello world
While adding string to my pointer's array, it is being overwriten by the last one. Could anyone tell me, where's my mistake?
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
int main (){
int ile = 3;
const char * slowa[ile];
for(int j = 0; j < ile; j++){
char string[30];
gets(string);
slowa[j] = string;
printf ("%s dodalem pierwsza\n",string);
}
for (int i = 0; i < ile; i++) {
printf ("%s numer %d\n",slowa[i],i);
}
return 0;
}
The answer is in the following two lines of code:
char string[30];
...
slowa[j] = string;
The assignment sets slowa[j] to the address of the same buffer, without making a copy. Hence, the last thing that you put in the buffer would be referenced by all elements of slowa[] array, up to position of j-1.
In order to fix this problem, make copies before storing values in slowa. You can use non-standard strdup, or use malloc+strcpy:
char string[30];
gets(string);
slowa[j] = malloc(strlen(string)+1);
strcpy(slowa[j], string);
In both cases you need to call free on all elements of slowa[] array to which you have assigned values in order to avoid memory leaks.
You're always pointing to array of chars which is stack variable it's locally allocated only in scope of function, possibly each declaration of string will be on the same address as previous iteration in your loop. You could either instead of using array of chars allocate memory each loop iteration or use array and then using i.e strdup allocate memory for your new string like
slowa[j] = strdup(string) :
As others have said, you need to create copies of the strings, otherwise you set the strings to the same address, and therefore they just overwrite each other.
Additionally, I think using fgets over gets is a much safer approach. This is because gets is very prone to buffer overflow, whereas with fgets, you can easily check for buffer overflow.
This is some code I wrote a while ago which is similar to what you are trying to achieve:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define PTRS 3
#define STRLEN 30
int
string_cmp(const void *a, const void *b) {
const char *str1 = *(const char**)a;
const char *str2 = *(const char**)b;
return strcmp(str1, str2);
}
int
main(void) {
char *strings[PTRS];
char string[STRLEN];
int str;
size_t len, i = 0;
while (i < PTRS) {
printf("Enter a string: ");
if (fgets(string, STRLEN, stdin) == NULL) {
fprintf(stderr, "%s\n", "Error reading string");
exit(EXIT_FAILURE);
}
len = strlen(string);
if (string[len-1] == '\n') {
string[len-1] = '\0';
} else {
break;
}
strings[i] = malloc(strlen(string)+1);
if (strings[i] == NULL) {
fprintf(stderr, "%s\n", "Cannot malloc string");
exit(EXIT_FAILURE);
}
strcpy(strings[i], string);
i++;
}
qsort(strings, i, sizeof(*strings), string_cmp);
printf("\nSuccessfully read strings(in sorted order):\n");
for (str = 0; str < i; str++) {
printf("strings[%d] = %s\n", str, strings[str]);
free(strings[str]);
strings[str] = NULL;
}
return 0;
}
I would like to create an array of string variables, and the number of elements is depends on the user's input. For example, if the user's input is 3, then he can input 3 strings. Let's say "aaa", "bbb" and "ccc". They are stored by the same pointer to char(*ptr) but with different index.
code:
int main()
{
int t;
scanf("%d", &t);
getchar();
char *ptr = malloc(t*sizeof(char));
int i;
for(i=0;i<t;i++)
{
gets(*(ptr[i]));
}
for(i=0;i<t;i++)
{
puts(*(ptr[i]));
}
return 0;
}
t is the number of elements, *ptr is the pointer to array. I would like to store "aaa", "bbb" and "ccc" in ptr[0], ptr[1] and ptr[2]. However, errors have been found in gets and puts statement and i am not able to work out a solution. Would someone give a help to me? Thank you!
You shouldn't use gets(), which has unavoidable risk of buffer overrun, deprecated in C99 and deleted from C11.
Only one character can be stored in char. If the maximum length of strings to be inputted is fixed, you can allocate an array whose elements are arrays of char. Otherwise, you should use an array of char*.
Try this (this is for former case):
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
/* the maximum length of strings to be read */
#define STRING_MAX 8
int main(void)
{
int t;
if (scanf("%d", &t) != 1)
{
fputs("read t error\n", stderr);
return 1;
}
getchar();
/* +2 for newline and terminating null-character */
char (*ptr)[STRING_MAX + 2] = malloc(t*sizeof(char[STRING_MAX + 2]));
if (ptr == NULL)
{
perror("malloc");
return 1;
}
int i;
for(i=0;i<t;i++)
{
if (fgets(ptr[i], sizeof(ptr[i]), stdin) == NULL)
{
fprintf(stderr, "read ptr[%d] error\n", i);
return 1;
}
/* remove newline character */
char *lf;
if ((lf = strchr(ptr[i], '\n')) != NULL) *lf = '\0';
}
for(i=0;i<t;i++)
{
puts(ptr[i]);
}
free(ptr);
return 0;
}
You can use this code which is given below because string array is like char 2D array so use can use pointer of pointer and when you allocate memory at run time by malloc then you need to cast into pointer to pointer char type.
int main()
{
int t;
scanf("%d", &t);
char **ptr = (char **)malloc(t*sizeof(char));
int i,j;
for( i=0;i<t;i++)
{
scanf("%s",ptr[i]);
}
for(i=0;i<t;i++)
{
puts(ptr[i]);
}
return 0;
}
Here is an example, of a clean if slightly memory inefficient way to handle this. A more memory efficient solution would use one string of MAX_LINE_LENGTH and copy to strings of precise lengths.. which is why one contiguous block of memory for the strings is a bad idea.
The asserts also just demonstrate where real checks are needed as malloc is allowed to fail in production where asserts do nothing.
#include <stdio.h>
#include <malloc.h>
#include <assert.h>
#define MAX_LINE_LENGTH 2048
int
main(void) {
int tot, i;
char **strheads; /* A pointer to the start of the char pointers */
if (scanf("%d\n", &tot) < 1)
return (1);
strheads = malloc(tot * sizeof (char *));
assert(strheads != NULL);
/* now we have our series of n pointers to chars,
but nowhere allocated to put the char strings themselves. */
for (i = 0; i < tot; i++) {
strheads[i] = malloc(sizeof (char *) * MAX_LINE_LENGTH);
assert(strheads[i] != NULL);
/* now we have a place to put the i'th string,
pointed to by pointer strheads[i] */
(void) fgets(strheads[i], MAX_LINE_LENGTH, stdin);
}
(void) printf("back at ya:\n");
for (i = 0; i < tot; i++) {
fputs(strheads[i], stdout);
free(strheads[i]); /* goodbye, i'th string */
}
free(strheads); /* goodbye, char pointers [0...tot] */
return (0);
}
I am trying to build a program that uses dynamic allocation to build an array of strings.
After the user finishes to enter the words he wants into the array i want to print the array one word after the other. I am using pointers to pointers, however it doesn't seem to work:
#define SIZE 256
void paintWords(char **words, int count_words);
void main() {
char **words = NULL;
int flag = 1;
char buffer[SIZE];
int count_words = 0;
char *curr_word;
while (flag)
{
_flushall();
printf("Enter a word:");
gets(buffer);
words = (char**)realloc(words,++count_words*sizeof(char*));
curr_word = (char*)malloc(strlen(buffer) + 1);
words[count_words - 1] = curr_word;
printf("Do you wish to continue(0-no, 1-yes):");
scanf("%d", &flag);
}
paintWords(words, count_words);
}
void paintWords(char **words, int count_words) {
int j = 0;
for (int i = 0; i < count_words; i++)
{
printf("%s\n", words[i][j]);
}
}
Copy buffer to your malloc'ed block with strcpy
strcpy(curr_word, buffer);
you are discarding the read word since you don't put it anywhere
Don't use gets use fgets instead
fgets(buffer, sizeof(buffer), stdin);
this would prevent a buffer overflow.
This is just the jst which in your case is the 0th character of the word
printf("%s\n", words[i][j]);
change it to
printf("%s\n", words[i]);
turn compiler warnings on, it would tell you about printf expecting a char * and recieving char instead.
Also consider the following:
main() should return int.
You don't need to cast malloc.
Don't overwrite your pointer with realloc, use a temporary pointer and assign it to array on success only. Otherwise if realloc returns NULL you will not be able to free(array) for example.
++count_words
words = realloc(words,count_words*sizeof(char*));
words[count_words-1] = malloc(strlen(buffer) + 1);
strcpy(words[count_words-1],buffer);
Later print the array
printf("%s\n",words[i]);
realloc() can fail so
char *temp = realloc(words,count_words*sizeof(char*));
if(temp != NULL)
words = temp;
Few other fixes will be
You shouldn't be using gets which is no more a standard. Use fgets() and note that fgets() comes with a newline character
Check the code below:
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#define SIZE 256
void paintWords(char **words, int count_words);
void main() {
char **words = NULL,ch;
int flag = 1;
char buffer[SIZE];
int count_words = 0;
//char *curr_word;
while (flag)
{
printf("Enter a word:");
fgets(buffer,sizeof(buffer),stdin);
words = (char**)realloc(words,++count_words*sizeof(char*));
words[count_words - 1] = (char*)malloc(strlen(buffer) + 1);
strcpy(words[count_words-1],buffer);
printf("Do you wish to continue(0-no, 1-yes):");
scanf("%d", &flag);
while((ch = getchar()) != '\n');
}
paintWords(words, count_words);
}
void paintWords(char **words, int count_words) {
int i;
for (i=0; i < count_words; i++)
{
printf("%s", words[i]);
}
}
I want the loop to break when "Enter" is pressed. Any suggestions?
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define len 20
#define limit 100
//Prototypes for functions
int read_word(char str[], int n);
int main(void)
{
char *p;
char word[len+1];
int i=0, nwords = 0;
//Loop for reading in words and allocating an array
for (;;)
{
if (nwords == limit)
{
printf("Insufficient Space\n");
break;
}
printf("Enter word: ");
scanf("%c", &word);
p = (char*) malloc(nwords*sizeof(char));
p[i]= read_word(word, len);
i++;
if (p == NULL)
{
printf("Insufficient Space\n");
break;
}
}
for(i=0; i<nwords; i++)
printf(" %s\n", p[i]);
return 0;
}
int read_word(char str[], int n)
{
char ch;
int i = 0;
while((ch = getchar()) != '\n')
if (i<n)
str[i++] = ch;
str[i] = '\0';
return i;
}
Your scanf call reads the first character, and then your read_word function overwrites it. If the scanf call reads the newline, it will then be ignored.
The lines:
p = (char*) malloc(nwords*sizeof(char));
p[i]= read_word(word, len);
... also appears wrong. read_word returns an integer (the length of the string read), but you are storing into a char array. Also, you are re-allocating the memory for p each time through the loop, so the values stored previously will be lost.
To fix:
change p to be an int *, and initialize it to null
change the malloc call to a suitable realloc
remove the call to scanf entirely
move the check for p == null before the assignment of `p = (char*) malloc(nwords*sizeof(char));'
Or: is p meant to actually be an array of strings (the words themselves) rather than the word length? In that case you have to:
change p to be an char **
change the allocation size (for the realloc call) to nwords * sizeof(*p)
allocate (using malloc) storage for each word instead of having word be a stack-allocated array
set p[i] = word; rather than the current assignment.