Global Array doesn't update while inside while loop? - c

I have an array of structs, inside the while loop I add things to that array, however when I print out the array I get the wrong output?
(The last element added is printed out n times, n being the number of things I added)
I have googled this and I think it is because a while loop in Bash creates a subshell, not too sure.
Any help would be much appreciated
(please have patience I am only a student!!)
Using Mac OSX mountain lion
Xcode 4 gcc
Code:
#include <stdio.h>
#include <limits.h>
#include <ctype.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/types.h>
typedef struct{
char* one;
char* two;
} Node;
Node nodes[100];
int count = 0;
void add(char *one,char*two){
Node newNode = {one,two};
nodes[count]= newNode;
printf("one: %s\n",one);
printf("two: %s\n",two);
count++;
}
void print(){
int x;
for (x = 0; x < 10; x++)
printf("%d : (%s, %s) \n",x,nodes[x].one, nodes[x].two);
}
void check(char **arg)
{
if(strcmp(*arg, "Add") == 0)
add(arg[1],arg[2]);
else if(strcmp(*arg,"print") == 0)
print();
else
printf("Error syntax Enter either: \n Add [item1][item2]\n OR \n print\n");
}
void readandParseInput(char *line,char **arg)
{
if (fgets (line, 512, stdin)!= NULL) {
char * pch;
pch = strtok (line," \n\t");
int count = 0;
arg[0] = pch;
while (pch != NULL)
{
count++;
pch = strtok (NULL, " \n\t");
arg[count] = pch;
}
}else{
printf("\n");
exit(0);
}
}
int main()
{
int i;
for(i = 0;i <100; i++){
nodes[i].one = ".";
nodes[i].two = ".";
}
char line[512]; /* the input line */
char *arg[50]; /* the command line argument */
while (1)
{
readandParseInput(line,arg);
if(arg[0] != NULL)
check(arg);
}
return(0);
}

strtok() returns a pointer to different elements within the buffer it was initially passed. This means that all entries in the array will be pointing to different elements of the same buffer, named line. You need to make a copy of the pointer returned by strtok():
use malloc(), strlen() and strcpy(). Or,
use the non-standard strdup()
in either case, the memory must be free()d when no longer required.

It's because you use the same buffer for all input.
You need to duplicate the strings you put into the structures. Either by using arrays for the strings and strcpy into them, or by using strdup to allocate new memory for the strings and do the copying in one function.

Related

How to add a string from user input into an array dynamically in C?

I want to create a simple C program where, inside a loop, when the user inputs a string, the string automatically gets added to an array. I'm lost on how to do that at runtime. Any help would be appreciated.
Edit: For clarification, here, 10 is the max size of the array. I was thinking of initializing the array with a number and then expanding that size (probably by a multiplier) when it reaches the max size (which is 10 in this case).
Edit2: More specifically, I want it to be so that the first iteration adds a string to the array, then the second iteration adds another inputted string to the array, and so on.
For now my code looks like this:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int main() {
char* strings[10];
char *input_str;
printf("enter a string: ")
strings = malloc(sizeof(char)*10); //not sure if this is required but included anyway
//run a loop here to keep adding the input string
fgets((char)input_str, 1024, stdin);
}
char* strings[10];
Notice that strings is a non resizable array of ten pointers to char, so it is not useful for dynamic allocation when you don't know the number of elements before hand.
I will use realloc over a char ** and the modulo operator to detect when to realloc, something like:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define MULTIPLE 10
int main(void)
{
char **strings = NULL;
char str[1024];
size_t size = 0;
while (fgets(str, sizeof str, stdin))
{
if ((size % MULTIPLE) == 0)
{
char **temp = realloc(strings, sizeof *strings * (size + MULTIPLE));
if (temp == NULL)
{
perror("realloc");
exit(EXIT_FAILURE);
}
strings = temp;
}
strings[size] = malloc(strlen(str) + 1);
if (strings[size] == NULL)
{
perror("malloc");
exit(EXIT_FAILURE);
}
strcpy(strings[size], str);
size++;
}
for (size_t i = 0; i < size; i++)
{
printf("%s", strings[i]);
free(strings[i]);
}
free(strings);
return 0;
}

How to get line from stdin and split it to tokens?

I am trying to write RPN calculator, but I've been struggling with getting arguments from user. What I want to do is: take whole line, split it to tokens and put it to array. I have something like below, but it works only once. On the second while-loop performing line is taken, but arr==NULL
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#define MAX_str 100
char* getLine(){
char* line = malloc(MAX_str*sizeof(char*));
return fgets(line, MAX_str,stdin);
}
char** toArray(char* line){
int i=0;
char** array= malloc(MAX_str*sizeof(char*));
array[i] = strtok(line," \t");
while(array[i]!=NULL){
array[++i] = strtok(NULL,"");
}
return array;
}
int main(){
char* linia;
char** arr;
int i=0,end=0;
while(!end){
linia=getLine();
arr = toArray(linia);
while(arr[i]!=NULL){
printf("%s\n",arr[i]);
i++;
}
free(linia);
free(arr);
}
}
Secondly, strtok splits only on two tokens, for example
>1 2 3
gives:
>1
>2 3
Code's primary problem is using an empty token string for subsequent calls of strtok(). Add as needed, characters to the 2nd token list
// array[++i] = strtok(NULL,"");
array[++i] = strtok(NULL," \t\n");
Improvement idea for getLine(): read and then allocate.
char* getLine(){
char buf[MAX_str];
if (fgets(buf, sizeof buf, stdin) == NULL) {
return NULL;
}
return strdup(buf);
}
strdup() is common, although not in the C standard. Code example.
Well, being stupid costs time... I have forgotten to reset i after while-loop in main()...
Is this code better? I want arr to be table of char pointers in amount of MAX_str. Is it declared well? With malloc would it be initialized like in answers above? To prevent array overflow I would compare i and value of MAX_str. Would it be ok?
#define MAX_str 100
char* getLine(){
char buf[MAX_str];
if (fgets(buf, sizeof buf, stdin) == NULL) {
return NULL;
}
return strdup(buf);
}
int toArray(char* line, char* array[MAX_str]){
int i=0;
array[i] = strtok(line," \t\n");
while(array[i]!=NULL){
array[++i] = strtok(NULL," \t\n");
}
return i;
}
int main(){
char* linia;
char* arr[MAX_str];
int i=0,end=0;
while(!end){
linia=getLine();
assert(linia!=NULL);
toArray(linia,arr);
assert(arr!=NULL);
while(arr[i]!=NULL){
printf("%s\n",arr[i]);
i++;
}
}
}

input a list of strings using dynamic allocation in c

I am trying to input a list of strings. The list may vary in length, so I try to use dynamic allocation. Each string has 20 chars max. The list ends with a single dot. I have been working on it for some time now, but I keep getting a segmentation fault and I am not sure why. I guess the error is in my use of realloc / malloc, but I just cannot see what exactly I am doing wrong. The code block is part of a larger program, but I singled out this block and am trying to make it work. It works fine for a "list" of one word followed by a dot. As soon as I try to read a list of two or more strings, I get the segmentation error.
Any help would be great, thanks!
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
char **resizeDynamicArray(char **arr, int newSize){
char **ptr = realloc(arr, newSize*sizeof(char*));
if (ptr==NULL) {
printf("Error: memory allocation failed.\n");
exit(-1);
}
return ptr;
}
int input (char ***seq){
int len = 0;
char string[21];
*seq=NULL;
do{
scanf("%s", string);
if (string[0] != '.'){
*seq = resizeDynamicArray(*seq, (len+1));
*seq[len] = malloc(sizeof(char[21]));
strcpy((*seq)[len], string);
len++;
}
} while (string[0] != '.');
return len;
}
int main(int argc, char *argv[]) {
int length;
char **words;
length = input(&words);
for (int i=0; i<length; ++i){
printf("%s\n", words[i]);
}
for (int i=0; i<length; ++i){
free(words[i]);
}
free(words);
return 0;
}
Change the following line:
*seq[len] = malloc(sizeof(char[21]));
to:
(*seq)[len] = malloc(sizeof(char[21]));
There is an extra level of indirection that needs to be dereferenced before you can index into the top-level array.

Array of pointers to char * in c using qsort

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

Create variable numbers of string variables according to users's input(C language)

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

Resources