Create and fill a dynamic array within function C - arrays

I need to scan n numbers and then fill an array with the following scanned n numbers. I have to use both n and array inputs in a function as well as to use dynamic memory.
void input(int* buff, int* n);
int main() {
int* data = NULL;
int n;
input(data, &n);
for (int i = 0; i < n; ++i) {
printf("%d ", data[i]);
}
return 0;
}
void input(int* buff, int *n) {
if (scanf("%d", n) == 1 && getchar() == '\n') {
if (*n <= 0) {
error = 1;
}
}
if (error == 0) {
buff = (int*)calloc(*n, sizeof(int));
if (buff == NULL) {
error = 1;
}
}
if (error == 0) {
int count = 0;
int p;
for (int i = 0; i < *n; i++) {
if (1 == scanf("%d", &p)) {
if (count < *n) {
*(buff + count) = p;
count++;
}
}
}
for (int i = 0; i < *n; i++) {
printf("%d, ", *(buff + i));
}
}
I didn't insert all the logic of my program in the first for since it doesn't really mater.
The last for prints proper elements however I have a warning about an empty pointer.
When I return to the main and trying to print I've got an error about read access prohibition.
Where did I do wrong?

data in main isn't changed when you change buff inside input. In other words - data will still be NULL when the input function returns.
It's just like the n... For n you correctly pass a pointer to n and you need to do exactly the same for data.
Like:
void input(int** buff, int *n) {
^^
// Notice the two *, i.e. pointer-to-pointer
....
*buff = calloc(....
....
and call it like
input(&data, &n);

If you only need to allocate one single dynamic array in your function you can just return a pointer to it:
int *input(int *buf, int *n);
...
data = input(data, &n);
...
int *input(int* buff, int *n) {
...
return buff;
}

Related

Where my code is leak? how i need to write free() function? C

This code scans number then he create array with malloc, then i scan strings, i put then inside the array with another malloc, then i sort the strings and print them. I build this code with mallocs and i put array inside array,i have leaks in this code, where i need to put free() function and how i put free()? I tried many times to solve this leaks but its not working.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
void sort(char** names, int length);
void print_array(char** names, int length);
int main()
{
int num_of_friends = 0;
int i = 0;
char name[50] = { 0 };
char** names = NULL;
printf("Enter number of friends: ");
scanf("%d", &num_of_friends);
getchar();
names = malloc(sizeof(char) * num_of_friends);
for ( i = 0; i < num_of_friends; i++)
{
printf("Enter name of friend %d: ", i + 1);
fgets(name, 50, stdin);
name[strcspn(name, "\n")] = 0;
names[i] = malloc(sizeof(char) * strlen(name));
strcpy(names[i], name);
}
sort(names, num_of_friends);
print_array(names, num_of_friends);
getchar();
return 0;
}
void sort(char** names, int length)
{
char temp[50] = { 0 };
int i = 0;
int j_min = 0;
int j = 0;
for ( i = 0; i < length - 1; i++)
{
j_min = i;
for ( j = i+1; j < length; j++)
{
if (strcmp(names[j], names[j_min]) < 0)
{
j_min = j;
}
}
if (j_min != i)
{
strcpy(temp, names[i]);
strcpy(names[i], names[j_min]);
strcpy(names[j_min], temp);
}
}
}
void print_array(char** names, int length)
{
int i = 0;
for (i = 0; i < length; i++)
{
printf("Friend %d: %s \n", i + 1, names[i]);
}
}
For names, you are allocating sizeof (char) times the user provided number of bytes. This is needs to be sizeof (char *), giving you enough room for each pointer value.
names = malloc(sizeof (char *) * num_of_friends);
You need to allocate one additional byte for the null terminating character ('\0'). sizeof (char) is guaranteed to be 1, making that statement redundant.
names[i] = malloc(strlen(name) + 1);
Before the end of main, you need to free each element of names, and then names itself.
sort(names, num_of_friends);
print_array(names, num_of_friends);
getchar();
for (i = 0; i < num_of_friends; i++)
free(names[i]);
free(names);
return 0;
Your sort function may attempt to copy strings between buffers of differing size. You need to swap pointers instead.
Example:
void swap(char **a, char **b) {
char *c = *a;
*a = *b;
*b = c;
}
void sort(char **names, size_t length) {
for (size_t i = 0; i < length - 1; i++)
for (size_t j = i + 1; j < length; j++)
if (strcmp(names[i], names[j]) > 0)
swap(names + i, names + j);
}

double free or corruption when using char**

I'm allocating memory for my int *occurrences int *wordCounts and char **uniqueWords pointers and then at the end of the function that allocates the memory, i free them. However, when i compile the program i get an double free or corruption (!prev) aborting error. Is it caused by malloc,free or could it be due to how i initialize them inside the for loop ?
PS: I'm talking about the sortedCount() method, located towards the end
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <math.h>
#define MAX_STRING_SIZE 512 /* each line in the file can have up to 512 chars */
void populateWordsArray(int);
void reverse(int);
void first(int);
void middle(int);
void last(int);
int count(int, char*, int);
void sortedCount(int);
void determineUniqueWords(int *,char **, int);
void *malloc_or_end(size_t);
void* malloc_or_end(size_t sz) {
void *pointer;
pointer = malloc(sz);
if(pointer == NULL) {
printf("Out of memory, terminating.\n");
exit(-1);
}
return pointer;
}
/* turn into local */
FILE *file;
char **wordList;
void determineUniqueWords(int *occurrences, char **word, int N) {
int i = 0;
int j = 0;
for(i = 0; i < N; i++) {
if(occurrences[i] < 1) {
continue;
}
for(j = i + 1; j < N; j++) {
if(occurrences[j] == 1 && (strcmp(word[i],word[j])) == 0) {
occurrences[i]++;
occurrences[j] = 0;
}
}
}
}
/**
* Function populateWordsArray: reads N words from
* the given file and populates the wordList array with them.
* Has one argument: int N - the number of words to read.
* */
void populateWordsArray(int N) {
int i = 0;
while(i < N && (fscanf(file,"%s",wordList[i]) == 1)) { /* fscanf returns the number of successfully read items. If it's not 1, the read failed. Same as checking if fscanf reads the eof char. */
i++;
}
}
/**
* Function reverse: prints the words of the
* text file in reverse order.
* */
void reverse(int N) {
int i = 0;
for(i = N-1; i >= 0; i--) {
if(i == 0) {
printf("%s \n",wordList[i]);
} else if(strcmp(wordList[i],"") == 0) { /* improve this in main-> memory allocation */
continue;
}else {
printf("%s ",wordList[i]);
}
}
return;
}
/**
* Function first: Prints the first char of each
* word in the file.
* */
void first(int N) {
char firstChar;
int i = 0;
for(i = 0; i < N; i++) {
firstChar = *wordList[i];
printf("%c",firstChar);
}
printf("\n");
return;
}
/**
* Function middle: Prints the middle char of each word
* from the given file.
* */
void middle(int N) {
int middleIndex = 0;
int i = 0;
char midChar;
for(i = 0; i < N; i++) {
if((strlen(wordList[i]) % 2) == 0) { /* artios */
middleIndex = ((strlen(wordList[i]) / 2) - 1);
midChar = wordList[i][middleIndex];
}
else { /* peritos */
middleIndex = (int) ceil((strlen(wordList[i]) / 2));
midChar = wordList[i][middleIndex];
}
printf("%c",midChar);
}
printf("\n");
return;
}
/**
* Function last: Prints the last char of each
* word from the given file.
* */
void last(int N) {
int i = 0;
char lastChar;
int lastPos;
for(i = 0; i < N; i++) {
lastPos = strlen(wordList[i]) - 1;
lastChar = wordList[i][lastPos];
printf("%c",lastChar);
}
printf("\n");
return;
}
/**
* Function count: Prints the number of times
* that the selected word is found inside the N first words
* of the file.
* */
int count(int N, char *word, int callID) {
int i = 0;
int count = 0;
for(i = 0; i < N; i++) {
if(strcmp(word,wordList[i]) == 0) {
count++;
}
}
if(callID == 0) { /* if callID == 0 (main called count and we want the output) */
printf("%d",count);
printf("\n");
}
return count;
}
void sortedCount(int N) {
int i,j = 0;
int *occurrences;
int *wordCounts;
char **uniqueWords;
/* mem allocation */
uniqueWords = malloc_or_end(N * sizeof(char*)); /* worst case: every word is unique */
wordCounts = malloc_or_end(N * sizeof(int));
occurrences = malloc_or_end(N * sizeof(int));
/* initialize rootWord and occurrences for the "each word is unique and occurs only once" scenario */
for(i = 0; i < N; i++) {
uniqueWords[i] = malloc_or_end(MAX_STRING_SIZE * sizeof(char));
occurrences[i] = 1;
}
determineUniqueWords(occurrences,wordList,N);
/* populate the wordCounts & uniqueWords "arrays" with the appropriate data in order to sort them successfully */
for(i = 0; i < N; i++) {
if(occurrences[i] > 0) {
wordCounts[i] = count(N,wordList[i],1);
uniqueWords[i] = wordList[i];
}
}
for(i = 0; i < N; i++) {
free(uniqueWords[i]);
}
free(uniqueWords);
free(occurrences);
free(wordCounts);
return;
}
int main(int argc,char *argv[]) { /* argv[1] = op argv[2] = name argv[3] = <word> */
int N = -1;
int i = 0;
int spaceNum,nlNum = -1;
file = fopen(argv[2],"r");
if(file == (FILE *) NULL) { /* check if the file opened successfully */
fprintf(stderr,"Cannot open file\n");
}
fscanf(file,"%d",&N); /* get the N number */
wordList = malloc_or_end(N * sizeof(char *)); /* allocate memory for pointers */
for(i = 0; i < N; i++) {
wordList[i] = malloc_or_end(MAX_STRING_SIZE * sizeof(char)); /* allocate memory for strings */
}
populateWordsArray(N);
if(strcmp(argv[1],"-reverse") == 0) {
reverse(N);
} else if(strcmp(argv[1],"-first") == 0) {
first(N);
} else if(strcmp(argv[1],"-middle") == 0) {
middle(N);
} else if(strcmp(argv[1],"-last") == 0) {
last(N);
} else if((strcmp(argv[1],"-count") == 0) && argv[3] != NULL) {
i = count(N,argv[3],0);
} else if((strcmp(argv[1],"-sorted") == 0) && (strcmp(argv[3],"-count") == 0)) {
sortedCount(N);
} else {
/* i only wish i could print something here */
}
/* End of program operations */
for(i = 0; i < N; i++) {
free(wordList[i]);
}
free(wordList);
fclose(file);
return 0;
}
You are overwriting the value of a pointer to heap memory on line 185:
uniqueWords[i] = wordList[i];
This means that when you free it later, you are actually freeing the allocated rows in wordList. Now you have two problems:
When you free the wordList rows on lines 244-246, it will be a double-free
You are losing your reference to the uniqueWords rows.
Use strcpy to assign to a dynamically-allocated string rather than the = operation.

I want to put some strings at dynamic 2D array with pointers(C programming)

Hi I want to get some strings from user then put those in 2D array and
at the end just print every character position in array for test.(Im writing at visual studio 2017)
but I'm getting output like this for example:
marray[1][2]==
marray[1][3]==
marray[1][3]==
and I'm getting this for all cells.
and here is my code so far:
#include <stdio.h>
#include <stdlib.h>
void inputnames(char**, int, int);
void printitems(char**, int, int);
int main(void)
{
int m;
const int n = 30; //students name limit
printf("Enter Number of students:");
scanf_s("%d ", &m); //getting row size from user
//---------------------------------------------
char** p;
p = (char**)malloc(sizeof(char)*m);
for (int i = 0; i < m; i++)
{ //this part for allocating 2d array
p[i] = (char*)malloc(sizeof(char)*n);
}
//--------------------------------------------
inputnames(p, m, n); //filling 2D array
printitems(p, m, n); //print each character with position for test
getchar();
}
void inputnames(char** marray, int mm, int nn)
{
int i = 0, j = 0;
for (i = 0; i<mm; i++)
{
while (marray[i][j] != '\n' && j<nn)
{
scanf_s("%c", &marray[i][j]);
}
}//end of for i
}
void printitems(char** marray, int mm, int nn) //this function is for test
{
int i = 0, j = 0;
for (i = 0; i<mm; i++)
{
for (j = 0; j<nn; j++)
{
printf("marray[%d][%d]=%c\n",i,j,marray[i][j]);
}//end of for j
}//end of for i
}
There are several error in your code.
Don't cast malloc. And your are allocating the incorrect number of bytes
both times. I advice you not to use sizeof(<type>), it's easy to make
mistakes, it's better practice to call malloc like this:
int *arr = malloc(size * sizeof *arr);
Regardless of the type of arr, you would allocate the correct amount of
memory.
You have to check if malloc returns NULL. If it returns NULL you cannot
access the memory.
Also remember that a string must be '\0'-terminated, for a string of length
n, you need n+1 bytes. You either allocate n+1 spaces for the strings, or
in inputnames you should check if j < nn - 1. Also you don't set the
'\0'-terminating byte in inputnames.
The correct allocation is:
char** p;
// calloc initializes the memory to 0,
// great initialization, helps you free the memory faster
// on error
p = calloc(m, sizeof *p);
if(p == NULL)
{
fprintf(stderr, "not enough memory\n");
return 1;
}
for (size_t i = 0; i < m; i++)
{
p[i] = calloc(1, n+1); // size of char is 1
if(p[i] == NULL)
{
fprintf(stderr, "not enough memory\n");
free_strings(p, m);
return 1;
}
}
And you would need the free_strings function:
void free_strings(char **strings, size_t len)
{
if(strings == NULL)
return;
for(size_t i = 0; i < len; ++i)
free(strings[i]);
free(strings);
}
Also your reading is not that efficient, I would use fgets instead:
int inputnames(char** marray, size_t mm, size_t nn)
{
if(marray == NULL || mm == 0 || nn == 0)
return 0;
for(size_t i = 0; i < mm; ++i)
{
printf("Enter text #%d: ", i+1);
fflush(stdout);
if(fgets(marray[i], nn, stdin) == NULL)
{
fprintf(stderr, "cannot read anymore\n");
return 0;
}
// removing the newline
marray[i][strcspn(marray[i], "\n")] = 0;
}
return 1;
}
I forgot to mention this in the answer:
for (i = 0; i<mm; i++)
{
while (marray[i][j] != '\n' && j<nn)
{
scanf_s("%c", &marray[i][j]);
}
}//end of for i
This yields undefined behaviour. You only allocate memory but you don't
initialize it, so you are actually checking if random value if equals to the
newline. You also don't increment j, you are writing always at the same place.
You need to read first, then check second.
for(i = 0; i<mm; i++)
{
do {
if(scanf_s("%c", marray[i] + j) != 1)
{
fprintf(stderr, "Unable to read from stdin\n");
marray[i][j] = 0;
return;
}
} while(marray[i][j++] != '\n' && j<nn);
marray[i][j-1] = 0; // setting the \0-terminating byte
}
and the printitems should look like this:
void printitems(char** marray, size_t mm)
{
if(marray == NULL || mm == 0 || nn == 0)
return;
for(size_t i = 0; i < mm; ++i)
puts(marray[i]);
}
Also don't forget to free the memory when you don't need it anymore.

Learning C trying to figure out this malloc stuff via functions

Hey I'm trying to figure out why the following code gets invalid write of size error from Valgrind at the line: array[i-1] = I;
I really don't now why my allocate_array function doesn't work. I tried so many things.
There are couple errors more but I just wanted to check first why this line is false or why my array isn't allocated.
Hope you can help me to figure out my error.
#include<stdio.h>
#include<stdlib.h>
//Programm to check Gaussian function
int read_number_from_stdin(int* value) {
printf("Number for the Gaussian Function: ");
int return_value = scanf("%d", value);
if (return_value == 0) {
while (fgetc(stdin) != '\n')
;
}
if (return_value == EOF) {
return_value = 0;
}
return return_value;
}
int read_number_from_string(char* string, int* value) {
printf("Reading input...\n");
int return_value = sscanf(string, "%d", value);
if (return_value == 0 || return_value == EOF) {
printf("\t... Error your input is not a Number!\n");
return_value = 0;
} else {
printf("\t... Number %d read and saved.\n", *value);
}
return return_value;
}
int* allocate_array(int* size) //allocating memory for the array
{
int* result = (int*) malloc(sizeof(int) * (*size));
return result;
}
void initialize_array(int array[], int size) {
for (int i = 0; i < size; i++) {
array[i] = i+1;
}
}
int compute_sum_and_place_in_first_elem(int array[], int* size) {
int sum_array = 0;
for (int i = 0; i < *size; i++) {
sum_array += array[i];
}
return sum_array;
}
void free_memory(int array[], int* N) {
free(array);
free(N);
}
int main(int argc, char* argv[]) {
int* N = malloc(sizeof(int));
if (argc == 1) {
while (read_number_from_stdin(N) != 1)
;
} else if (argc == 2) {
if (read_number_from_string(argv[1], N) == 0) {
printf("Error: No valid number!\n", argv[1]);
return -1;
}
} else {
printf("No valid number!\n");
return -1;
}
int* array = allocate_array(N); //allocate via function
initialize_array(array, *N); //initialize the array up to n
int result = compute_sum_and_place_in_first_elem(array, N);
int result_gauss = ((*N + 1) * (*N) / 2);
if (result == result_gauss) {
printf("Gauss was right your calculations match with his function");
} else {
printf(
"\nGauss was not right!\n"
"The summ of %d is %d and therefore not equal to(%d+1)*%d/2\n\n",
*N, result, *N, *N);
}
//free memory
free_memory(array, N);
}
As I can see, for the initialize_array() function, for the for loop, very first iteration, i is 0, and you're executing
array[i-1] = i;
which translates to
array [-1] = ....
which is illegal.
You can fix that using the default C-array property of 0-based indexing scheme. Something like
for(int i = 0; i < size; ++i)
{
array[i] = i;
}

Bus error: 10. No errors when compiling

So basically when I compile my code with a GCC compiler I get no error or warnings, but when I input the first piece of data it says:
Bus error: 10.
I'm not sure what I'm doing wrong. I think The problem is coming from void anagramGrouping (the last function). I also included the rest of the code to help follow the logic.
#include <stdio.h>
#include <string.h>
#define Row 2
#define col 20
int wordCount = 0;
int groupCount = 0;
char wordList[Row][col];
char group[Row][col];
// this is where prototypes go
void sortword(char word[col]);
void anagramGrouping(char word[col], char copy[col]);
void resetGroup();
int main() {
int i; // used in for loop to 'get' the strings
char word[col];
resetGroup();
for (i = 0; i < Row; i++) {
scanf("%s", word);
sortword(word);
wordCount++;
}
}
void resetGroup() {
int i;
for (i = 0; i < Row; i++)
strcpy(group[i], " ");
}
void sortword(char word[col]) {
int i = 0;
char temp;
char copy[col]; // used to store a copy of the original word
strcpy(copy, word);
while (word[i] != '\0') {
int j = i + 1;
while (word[j] != '\0') {
if (word[j] < word[i]) {
temp = word[i];
word[i] = word[j];
word[j] = temp;
}
j++;
}
i++;
}
anagramGrouping(word,copy);
}
void anagramGrouping(char word[col], char copy[col]) {
int n;
if (wordCount == 0) {
strcpy(group[0], copy);
}
for (n = 0; n <= groupCount; n++) {
if (strcmp(group[n], word) == 0) {
strcpy(group[n], copy);
} else {
groupCount++;
strcpy(group[groupCount], copy);
}
}
}
For starters, change all
sortword (char word[col])
to
sortword (char *word)
and all
anagramGrouping (char word[col], char copy[col])
to
anagramGrouping (char *word, char *copy)
When you pass char copy[col], you are passing a character array, which when passed as a function parameter is converted to a pointer. (you will hear the phrase "decays to a pointer", which isn't entirely correct, but is used often to mean the same thing). This isn't the problem causing the bus error, but will make your code much more readable.
Next, your bus error is generally due to the misuse of a pointer value which when the value is taken, falls outside the allowable memory range for your program, usually in the system area causing the bus error. Looking over your code, it is hard to tell which of the many issues may be the exact cause. However, a likely culprit is:
for(n=0; n <= groupCount; n++)
{
if ( strcmp(group[n],word) ==0 )
{
strcpy(group[n],copy);
}
else
{
groupCount++;
strcpy(group[groupCount],copy);
}
}
Where running through a debugger, you will quickly find that groupCount grows well beyond 1 causing strcpy(group[groupCount],copy) to write beyond the end of the char group[Row][col];. Where the allowable row values are limited to 0-1 as you #define Row 2.
To limit the copies to the allowable range, change the loop criteria to:
for (n = 0; n < Row; n++) {
A further cleanup of your code could look as follows:
#include<stdio.h>
#include<string.h>
#define Row 2
#define col 20
int wordCount = 0;
int groupCount = 0;
char wordList[Row][col];
char group[Row][col];
void sortword (char *word);
void anagramGrouping (char *word, char *copy);
void resetGroup();
int main (void) {
int i;
char word[col] = "";
resetGroup();
for (i = 0; i < Row; i++)
{
scanf ("%s", word);
sortword (word);
wordCount++;
}
return 0; /* main is a function of type 'int' and returns a value */
}
void resetGroup()
{
int i;
for (i = 0; i < Row; i++)
*group[i] = 0;
}
void sortword (char *word)
{
int i = 0;
char temp;
char copy[col] = "";
strcpy (copy, word);
while (word[i]) {
int j = i + 1;
while (word[j]) {
if(word[j] < word[i]) {
temp = word[i];
word[i] = word[j];
word[j] = temp;
}
j++;
}
i++;
}
anagramGrouping (word,copy);
}
void anagramGrouping (char *word, char *copy)
{
int n;
if (!wordCount)
strcpy (group[0],copy);
for (n = 0; n < Row; n++) {
if (strcmp (group[n], word) == 0)
strcpy(group[n],copy);
else {
groupCount++;
strcpy (group [groupCount],copy);
}
}
}
Let me know if you have any questions.

Resources