Halil
Halil

Reputation: 45

Using String Arrays in C

I tried to store strings in an array. But there is a mistake. My code is here:

#include <stdio.h>
#include <string.h>
#include <math.h>
#include <malloc.h>

const long long max_size = 2000;         // max length of strings
const long long N = 40;                  // number of closest words that will be shown
const long long max_w = 50;              // max length of vocabulary entries

int main(int argc, char **argv) {
  FILE *f;
  char st1[max_size];
  char kelimeler[max_size];     
  char *kelimelerim[max_size];  //string array initialization here
  char *bestw[N];
  char file_name[max_size], st[100][max_size];
  float dist, len, bestd[N], vec[max_size];
  long long words, size, a, b, c, d, cn, bi[100];
  char ch;
  float *M;
  char *vocab;

  strcpy(file_name, argv[1]);
  f = fopen(file_name, "rb");
  if (f == NULL) {
    printf("Input file not found\n");
    return -1;
  }


  fscanf(f, "%lld", &words);
  fscanf(f, "%lld", &size);
  vocab = (char *)malloc((long long)words * max_w * sizeof(char));
  for (a = 0; a < N; a++) bestw[a] = (char *)malloc(max_size * sizeof(char));
  M = (float *)malloc((long long)words * (long long)size * sizeof(float));
  if (M == NULL) {
    printf("Cannot allocate memory");
    return -1;
  }

  for (b = 0; b < words; b++) {
    a = 0;
    int sayac=0;
    while (1) {
      sayac++;  
      vocab[b * max_w + a] = fgetc(f);
      if (feof(f) || (vocab[b * max_w + a] == ' ')) {

        strcpy(kelimeler,&vocab[b * max_w + a-sayac+2]);  //gets the string here
        kelimelerim[b] = kelimeler;                      //and store it into string array here
        printf("%s %lld\n",kelimelerim[b],b); 
        sayac=0;
        break;

      }
      if ((a < max_w) && (vocab[b * max_w + a] != '\n')) 
        a++;
    }
    vocab[b * max_w + a] = 0;
    for (a = 0; a < size; a++) 
    fread(&M[a + b * size], sizeof(float), 1, f);
    len = 0;
    for (a = 0; a < size; a++) 
    len += M[a + b * size] * M[a + b * size];
    len = sqrt(len);
    for (a = 0; a < size; a++) 
    M[a + b * size] /= len;
  }
  fclose(f);

  int index;
  for (index = 0; index < words; index ++){
      printf("%s %d \n",kelimelerim[index ], index );
  }
  // here, the loop prints last string stored into array, for all indexes.       

I deleted the unimportant rows. When I run the above code and print the kelimelerim array, the last string is printed for all indexes of the array. Where is my mistake? Could you help me, please.

Upvotes: 1

Views: 109

Answers (3)

alk
alk

Reputation: 70931

This

kelimelerim[b] = kelimeler; 

does not copy any data, but only stores the address of kelimeler to kelimelerim[b]. If then looping over kelimelerim[b]'s elements, only references to kelimeler are found and as kelimeler gets re-used for each iteration, it contains the string read last, which then in turn is printed for each of element of kelimelerim[b].


Update:

To fix this either replace kelimelerim[b] by an array of "string" not just pointers to strings and do

strcpy(kelimelerim[b], kelimeler);

or dynamically create a real copy of kelimeler by doing:

kelimelerim[b] = strdup(kelimeler);

Be aware that for this latter case each call to strdup() allocates memory from the heap, which you shall free if not used anymore, by calling free() on each elelment of kelimelerim.

Also strdup() isn't Standard C but a POSIX extension. You might need to #define something to have it avaliable. See your implementation's documentaion on strdup() for details.


If strdup() is not available you might like to use this:

#include <stdlib.h> /* for malloc() */
#include <string.h> /* for strcpy() */
#include <errno.h> /* for errno */

char * strdup(const char * s)
{
  char * p = NULL;

  if (NULL == s)
  {
    errno = EINVAL;
  }
  else
  {
    p = malloc(strlen(s) + 1);
    if (NULL == p)
    {
      errno = ENOMEM;
    }
    else
    {
      strcpy(p, s);
    }
  }

  return p;
}

Upvotes: 0

4pie0
4pie0

Reputation: 29724

You are using char *vocab; as uninitialized pointer. This results in undefined behavior. You have to initialize this pointer before using it with a valid memory ( e.g. using malloc).

Upvotes: 0

NPE
NPE

Reputation: 500357

You never initialize vocab, so the following has undefined behaviour:

  vocab[b * max_w + a] = fgetc(f);

From that point on, all bets are off.

Upvotes: 1

Related Questions