I'm trying to extract all numbers from a string add 56 89 29. There is something wrong with my code which I'm not able to figure out. The output looks like this:
Current no: 56
Current no: 89
Current no: 9
Current no: 29
Current no: 9
Current no: 9
Current no: 0
Current no: 0
where as, I would expect this:
Current no: 56
Current no: 89
Current no: 29
Current no: 29
Current no: 29
Current no: 29
There are better ways to do it but I want to know what is wrong with this implementation.
#include <string.h>
#include <stdio.h>
int main(int argc, char * argv[]){
char temp[100];
char op[3];
char *buf = "add 56 89 29";
int offset = 0;
int rcount = 0;
int lastno = -999;
int currno;
bzero(&temp, sizeof(temp));
sscanf(buf, "%s", op); // Get the operator (add)
if(!strcmp(op, "add")){
while(1){
sscanf(buf + offset + 4, "%s", temp); // strlen("add ") == 4
currno = atoi(temp);
offset += strlen(temp);
if(currno == lastno){
rcount++;
// Repeating numbers means string finished
if(rcount == 3){
break;
}
}
printf("Current no: %d\tOffset: %d\n", currno, offset + 4);
lastno = currno;
}
}
return 0;
}
Thanks in advance!
The "%n" specifier will record the number of characters used by a scan. The result can be added to the offset to advance through the string.
#include <string.h>
#include <stdio.h>
int main(int argc, char * argv[]){
char temp[100];
char op[4];
char *buf = "add 56 89 29";
int offset = 0;
int used = 0;
int rcount = 0;
int lastno = -999;
int currno;
bzero(&temp, sizeof(temp));
sscanf(buf, "%3s%n", op, &used); // Get the operator (add)
offset += used;
if(!strcmp(op, "add")){
while( ( sscanf(buf + offset, "%99s%n", temp, &used)) == 1) {
currno = atoi(temp);
offset += used;
printf("Current no: %d\tOffset: %d\n", currno, offset);
lastno = currno;
}
}
return 0;
}
There are a few things I can see that would cause your program to fail
It's unecessary to write a loop like while (1) and then check for the variable inside the loop to break, because there is do {} while ();, this makes the code hard to understand.
This initialization bzero(&temp, sizeof(temp)); is wrong, unecessary, and inefficient. And also, bzero() is deprecated use memset().
You have a very important mistake in scanf("%s", op); you allocate space for 3 characters and type add which requires 3 + 1 for the nul terminator. The correct way to do it would be
char op[4];
if (sscanf(buf, "%3s", op) != 1)
{
fprintf("unexpected problem while reading the operator.\n");
return -1;
}
sscanf(buf + offset + 4, "%s", temp) is very dangerous too, because you could easily overflow buf or temp, and besides it's much more readable like this
sscanf(&buf[offset + 4], "%s", temp)
This implementation would work better
#include <string.h>
#include <stdio.h>
int main(int argc, char * argv[])
{
char op[4];
const char *buffer;
int count;
int last;
int length;
int offset;
const char *pointer;
buffer = "add 56 89 29";
if (sscanf(buffer, "%3s%n", op, &length) != 1)
{
fprintf(stderr, "unexpected problem while reading the operator.\n");
return -1;
}
pointer = &buffer[length];
if (strcmp(op, "add") != 0)
{
fprintf(stderr, "sorry, I can't understand this operator `%s'.\n", op);
return -1;
}
count = 0;
last = -999;
offset = length;
do {
int number;
int length;
if (sscanf(pointer, "%d%n", &number, &length) != 1)
{
fprintf(stderr, "input format error, exiting.\n");
return -1;
}
pointer += length;
if (number == last)
++count;
printf("Current no: %d\tOffset: %d\n", number, offset);
last = number;
offset += length;
} while ((count < 3) && (*pointer != '\0'));
return 0;
}
read about the scanf() "%n" specifier.
You can also use strtol() like this
#include <string.h>
#include <stdio.h>
int main(int argc, char * argv[])
{
char op[4];
char buffer[] = "add 56 89 29";
int count;
int last;
int length;
int offset;
char *pointer;
if (sscanf(buffer, "%3s%n", op, &length) != 1)
{
fprintf(stderr, "unexpected problem while reading the operator.\n");
return -1;
}
pointer = &buffer[length];
if (strcmp(op, "add") != 0)
{
fprintf(stderr, "sorry, I can't understand this operator `%s'.\n", op);
return -1;
}
count = 0;
last = -999;
offset = length;
do {
int number;
char *previous;
previous = pointer;
number = strtol(pointer, &pointer, 10);
if (number == last)
++count;
printf("Current no: %d\tOffset: %d\n", number, offset);
last = number;
offset += pointer - previous;
} while ((count < 3) && (*pointer != '\0'));
return 0;
}
Hi I tried your code and the following worked for me. I am not a hardcore C programmer so please forgive me if I am used any non standard C functions here and but I love to work in C.
int main(int argc, const char * argv[])
{
char *buf = "add 56 89 29";
int sum = 0;
if(!strncmp(buf, "add", 3))
{
buf += 3;
while(*buf != '\0')
{
if(isdigit(*buf) == 0)
{
++buf;
continue;
}
int digit;
int num = 0;
while(isdigit(*buf))
{
digit = (int)*buf - 48;
num = (num * 10) + digit;
++buf;
}
sum += num;
printf("Current no: %d\t Sum: %d\n", num, sum);
}
}
return 0;
}
A much better and convenient way of doing this is with strtok which you can use to get tokens one after the other.
#include <stdio.h>
#include <string.h>
int main(int argc, char * argv[]){
char *buf = "add 56 89 29";
char *token;
int count = 0;
token = strtok(buf, " ");
while(token != NULL){
count++;
if(count == 1)
continue;
printf("%s\n", token)
token = strtok(NULL, " ");
}
}
Related
I have the following inputs:
23 34 43 56 45
100 73
I want to input these two strings in different arrays integer arrays using pointer since the input size is apriori unknown.
I have written the following code, but I cannot get the integers into any of the two arrays.
#include <stdio.h>
#include <stdlib.h>
#define lent(x) (sizeof(x) / sizeof(x[0]))
#define Malloc(n, type) (type *)malloc((unsigned)((n) * sizeof(type)))
#define Realloc(ptr, n, type) (type *)realloc(ptr, (n) * sizeof(type))
void getInt_Stream(int *ptr)
{
int i = 0;
ptr = Malloc(i+1, int);
char c;
scanf("%c", &c);
while ((c != EOF) && (c != '\n'))
{
if (c >= '0' && c <= '9')
{
ptr[i] = ptr[i] * 10 + (c - '0');
}
else if (c == ' ')
{
i++;
ptr = Realloc(ptr, i+1,int);
ptr[i] = 0;
}
scanf("%c", &c);
}
}
int main()
{
int *arr1, *arr2;
getInt_Stream(arr1);
getInt_Stream(arr2);
int n1 = lent(arr1);
for (int i = 0; i < n1; i++)
{
printf(" arr1[%d] =%d\n", i, *(arr1+i));
}
return 0;
}
Also, I am getting some errors and warnings when I compile the program using
gcc prog.c -o prog -Wall -Wextra.
Please help with some hints. Thanks in advance.
Would you please try the following:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
/*
* get integer values from the file stream
* return the pointer to the array of integers
* the size of the array is stored in *n
*/
int *
getInt_Stream(FILE *fp, int *n)
{
char str[BUFSIZ]; // line buffer of the input stream
char *tk; // pointer to each token
char delim[] = " "; // delimiter of the tokens
int *arr = NULL; // array of intergers
int count = 0; // token counter
if (NULL == (fgets(str, BUFSIZ, fp))) {
// read a line and assign str
perror("fgets");
exit(1);
}
for (tk = strtok(str, delim); tk != NULL; tk = strtok(NULL, delim)) {
// get token one by one
if (NULL == (arr = realloc(arr, (count + 1) * sizeof(int)))) {
// allocate memory for the array
perror("realloc");
exit(1);
}
arr[count] = (int)strtol(tk, (char **)NULL, 10);
// assign the array element to int
count++;
}
*n = count; // number of the elements
return arr; // pointer to the array
}
int
main(int argc, char *argv[])
{
int *arr1, *arr2;
int n1, n2;
char *filename = argv[1];
FILE *fp;
int i;
if (argc != 2) {
fprintf(stderr, "usage: %s file.txt\n", argv[0]);
exit(1);
}
if (NULL == (fp = fopen(filename, "r"))) {
perror(filename);
exit(1);
}
arr1 = getInt_Stream(fp, &n1);
for (i = 0; i < n1; i++) {
printf("arr1[%d] = %d\n", i, arr1[i]);
}
arr2 = getInt_Stream(fp, &n2);
for (i = 0; i < n2; i++) {
printf("arr2[%d] = %d\n", i, arr2[i]);
}
free(arr1);
free(arr2);
fclose(fp);
return 0;
}
Output for the provided file:
$ ./a.out file.txt
arr1[0] = 23
arr1[1] = 34
arr1[2] = 43
arr1[3] = 56
arr1[4] = 45
arr2[0] = 100
arr2[1] = 73
I want to fill an array of char pointers in the following format:
[name, number of email addresses, all the email addresses]*number of people. The number of mail adresses for each person isn't known at first.
I have to use char *contacts[N]
When printing the array it only prints contacts[0], so I guess my way of scanning the input is wrong
This is my main so far:
int main()
{
char *contacts[N];
int nextAvailable = 0;
int * const nextAvailableP = &nextAvailable;
add(contacts, nextAvailableP);
//Printing this way will only print contacts[0]
int i;
for (i = 0; i < nextAvailable; i++) {
printf("%s", contacts[i]);
}
}
This is the add function:
int add(char *contacts[], int *nextAvailableP) {
if (*nextAvailableP > 97) {
printf("Not enough memory\n");
return FALSE;
}
char tempName[50];
char tempMail[50];
int numberOfMails = 1;
printf("Enter your name\n");
fgets(tempName, 50, stdin);
if ((strlen(tempName) > 0) && (tempName[strlen(tempName) - 1] == '\n'))
tempName[strlen(tempName) - 1] = '\0';
contacts[*nextAvailableP] = (char *)malloc((strlen(tempName) + 1));
if (contacts[*nextAvailableP] == NULL) {
printf("Not enough memory\n");
return FALSE;
} else {
strcpy(contacts[*nextAvailableP], tempName);
}
(*nextAvailableP)++;
int numberOfMailsIndex = *nextAvailableP;
itoa(numberOfMails, contacts[numberOfMailsIndex], 10);
(*nextAvailableP)++;
printf("Enter your mail/s, use enter to enter a mail and '-1' to signal you finished\n");
fgets(tempMail, 50, stdin);
while (strcmp(tempMail, "-1") != 0) {
if ((strlen(tempMail) > 0) && (tempMail[strlen(tempMail) - 1] == '\n')) {
tempMail[strlen(tempMail) - 1] = '\0';
}
contacts[*nextAvailableP] = (char *)malloc((strlen(tempMail) + 1));
if (contacts[*nextAvailableP] == NULL) {
printf("Not enough memory");
return FALSE;
} else {
strcpy(contacts[*nextAvailableP], tempMail);
}
(*nextAvailableP)++;
numberOfMails++;
itoa(numberOfMails, contacts[numberOfMailsIndex], 10);
fgets(tempMail, 50, stdin);
}
}
I thought I was initializing each cell in contacts to the requested size and then copying the word I scan from the user into it - but obviously I'm not. Should I iterate through each memory I've allocated char by char?
Btw, I know that the casting to *char isn't necessary
So this would be your corrected code
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#define MAX_ENTRIES 50
int add(char *contacts[], int *nextAvailable);
int main(void){
int i;
char *contacts[MAX_ENTRIES];
int nextAvailable = 0;
add(contacts, &nextAvailable);
add(contacts, &nextAvailable);
for(i=0; i < nextAvailable ; i++){
printf("%s\n", contacts[i]);
}
}
char* intToString(int val, int base){
//source: www.strudel.org.uk/itoa/
static char buf[32] = {0};
int i = 30;
for(; val && i ; --i, val /= base)
buf[i] = "0123456789abcdef"[val % base];
return &buf[i+1];
}
int add(char *contacts[], int *nextAvailableP) {
if (*nextAvailableP > 97) {
printf("Not enough memory\n");
return 0;
}
char tempName[50];
char tempMail[50];
int numberOfMails = 1;
printf("Enter your name\n");
fgets(tempName, 50, stdin);
if ((strlen(tempName) > 0) && (tempName[strlen(tempName) - 1] == '\n'))
tempName[strlen(tempName) - 1] = '\0';
contacts[*nextAvailableP] = (char *)malloc((strlen(tempName) + 1));
if (contacts[*nextAvailableP] == NULL) {
printf("Not enough memory\n");
return 0;
} else {
strcpy(contacts[*nextAvailableP], tempName);
}
(*nextAvailableP)++;
int numberOfMailsIndex = (*nextAvailableP);
contacts[numberOfMailsIndex] = malloc(5);
(*nextAvailableP)++;
printf("Enter your mail/s, use enter to enter a mail and '-1' to signal you finished\n");
fgets(tempMail, 50, stdin);
while (strcmp(tempMail, "-1\n") != 0) {
if ((strlen(tempMail) > 0) && (tempMail[strlen(tempMail) - 1] == '\n')) {
tempMail[strlen(tempMail) - 1] = '\0';
}
contacts[*nextAvailableP] = (char *)malloc((strlen(tempMail) + 1));
if (contacts[*nextAvailableP] == NULL) {
printf("Not enough memory");
return 0;
} else {
strcpy(contacts[*nextAvailableP], tempMail);
}
(*nextAvailableP)++;
numberOfMails++;
fgets(tempMail, 50, stdin);
}
strcpy(contacts[numberOfMailsIndex], intToString(numberOfMails - 1,10));
}
Your function add could be cut in a subfunction which gets a string from the user. This string will be stored in a allocated memory space which has the size of string.
Keep in mind : It's not a good practice to mix data of different nature in one array (names and email). It would be better to use structs (as #Barmar said).
I would do following steps:
Get name from user (char *)
Allocate memory and copy the name into it.
insert the pointer to this allocated memory into your array (contacts)
Get a email address put it in a dynamic allocated memory space
add its pointer to your array (Contacts
Increment emails counter
repeat
-1 detected
convert your email counter to string and the pointer into your array
Anyway here's a code that you can start play with:
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#define MAX_ENTRIES 50
#define BUFFERSIZE 50
int add(char *contacts[], int *nextAvailable);
char *getString(char *queryText);
char* intToString(int val, int base);
int main(void){
int i;
char *contacts[MAX_ENTRIES];
int nextAvailable = 0;
add(contacts, &nextAvailable);
add(contacts, &nextAvailable);
for(i=0; i < nextAvailable ; i++){
printf("%s", contacts[i]);
}
}
int add(char *contacts[], int *nextAvailable){
if(*nextAvailable > MAX_ENTRIES - 1){
printf("Not enough memory\n");
return 1;
}
contacts[*nextAvailable] = getString("Enter your name\n");
if(contacts[*nextAvailable] == NULL){
printf("Malloc Error\n");
return 1;
}
++(*nextAvailable);
int counterfield = *nextAvailable;
++(*nextAvailable);
int emailCounter = 0;
while(1){
if(*nextAvailable > MAX_ENTRIES - 1){
printf("Not enough memory\n");
return 1;
}
char *email = getString("Enter email\n");
if(strcmp(email, "-1\n") == 0){
contacts[counterfield] = malloc(5);
contacts[counterfield] = intToString(emailCounter, 10);
return 0;
}
emailCounter++;
contacts[*nextAvailable] = email;
++(*nextAvailable);
}
}
char *getString(char *queryText){
char buffer[BUFFERSIZE];
char *ret;
printf("%s", queryText);
fgets(buffer, BUFFERSIZE, stdin);
ret = malloc(strlen(buffer));
strcpy(ret, buffer);
return ret;
}
char* intToString(int val, int base){
//source: www.strudel.org.uk/itoa/
static char buf[32] = {0};
int i = 30;
for(; val && i ; --i, val /= base)
buf[i] = "0123456789abcdef"[val % base];
return &buf[i+1];
}
I am reading text from an input file in. I have to separate text from scores ie
John Doe 100 95 67 85
jane doe 67 78 99
and then average the numbers. I can separate by the spaces using strtok but how can i tell when i have an integer? i need to split the reading of names and of integers into 2 functions. My code to read it works but i need to stop at the end of each name. I attempted to use numbers converted to strings and using strcmp however it did not work.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
void read_reverse_write(FILE * ptr_file, FILE * op);
void write_and_avarage(int * fp, char * op);
//int checker(char *token);
int main(int argc, char** argv) {
FILE *fp;
FILE *op;
//opens quiz and checks and checks to make sure it did
fp = fopen("quiz.txt", "r");
if (fp == NULL) {
printf("Error opening file");
return (-1);
}
//opens op and checks that it did
op = fopen("output.txt", "w");
if (op == NULL) {
printf("Error opening file");
return (-1);
}
// runs read reverse write
read_reverse_write(fp, op);
fclose(fp);
fclose(op);
return (EXIT_SUCCESS);
}
void read_reverse_write(FILE * ptr_file, FILE * op) {
char buf[1000];
char *token;
const char delim[2] = " ";
fgets(buf, 1000, ptr_file);
token = strtok(buf, delim);
while (token != 100) {
fprintf(op, "%s ", token);
token = strtok(NULL, delim);
}
}
/*void write_and_avarage(int * fp, char * op) {
}
int checker(char *token) {
char *arr[102];
char ph[4];
for (int p = 0; p < 100; p++) {
if (p < 10) {
snprintf(ph, 1, "%d", p);
arr[p] = ph;
} else if (p < 99) {
snprintf(ph, 2, "%d", p);
arr[p] = ph;
} else if (p = 100) {
snprintf(ph, 3, "%d", p);
arr[p] = ph;
}
}
for (int z = 0; z < 100; z++) {
if (strcmp(token, arr[z]) == 1) {
return 1;
} else {
z++;
}
return 0;
}
}
*/
You can use the following code to check the whether the string is a number or not.
#include <stdio.h>
#include <string.h>
#define MAX_NUM 9
#define MIN_NUM 0
#define ZERO 0
#define MAX_SIZE 1024
int checkDigit(int num, int len)
{
int divisor = 1, checkVal = 0;
if(len <= 2)
divisor = 10;
else if(len > 2)
{
len = len - 1;
while(len != ZERO)
{
divisor = divisor * 10;
len = len - 1;
}
}
checkVal = num/divisor;
if(checkVal > MIN_NUM && checkVal <= MAX_NUM)
return 1;
else
return 0;
}
void main()
{
char array[MAX_SIZE] = "JOHN DOE 120 DOE HELLO 2323 90909";
char *split_token = NULL;
int status = 2, len = 0, sum = 0, total_digits = 0;
float average = 0;
split_token = strtok(array, " ");
while( split_token != NULL )
{
len = strlen(split_token);
status = checkDigit(atoi(split_token), len);
if (1 == status)
{
sum = sum + atoi(split_token);
total_digits = total_digits + 1;
}
split_token = strtok(NULL, " ");
}
average = (float)sum/total_digits;
printf("Average is : %f\n", average);
}
This code will check whether your string is a number or not and finally calculate the average of all the numbers in the given string.
If you need to read from a file, multiple sets of inputs, use fscanf() and use the complete code logic repeatedly for each line of input.
Hope it helps! Do ask if you need the complete code or any clarification for the code.
I want to convert a comma separated char* to an uint32_array[] in C. Is there an easy method/routine to do that?
I already spend a lot of time on SO and found many solutions on C++, but not an C like that :
Parsing a comma-delimited std::string
But I think it is not a good solution to cast from char* to string to string stream to vector and work with the vector.
char input[] = "1 , 2 , 34, 12, 46, 100";
to
uint32_t output[] = { 1 , 2 , 34, 12, 46, 100 };
I would appreciate any kind of help. Thanks a lot.
Here's a recursive algorithm that only makes a single pass. It allocates at the deepest level and fills in on the way out:
int *cvt(char *input, int *level)
{
char *cp = strtok(input, ", ");
if (cp == NULL) {
/* No more separators */
return (int *) malloc(sizeof(int) * *level);
}
int my_index = -1;
int n;
if (sscanf(cp, "%d", &n) == 1) {
my_index = *level;
*level += 1;
} else {
printf("Invalid integer token '%s'\n", cp);
}
int *array = cvt(NULL, level);
if (my_index >= 0) {
array[my_index] = n;
}
return array;
}
Call with:
int main(int ac, char **av)
{
char input[] = "1, 2, bogus, 4, 8, 22, 33, 55";
int n_array = 0;
int *array = cvt(input, &n_array);
int i;
printf("Got %d members:\n", n_array);
for (i = 0; i < n_array; ++i)
printf("%d ", array[i]);
printf("\n");
return 0;
}
One method (of many):
int converted = 0 ;
char* tok = input ;
int i = 0 ;
do
{
converted = sscanf( tok, "%d", &output[i] ) ;
tok = strchr( tok, ',' ) + 1 ;
i++ ;
} while( tok != NULL && converted != 0 ) ;
You could use strtok() instead of sscanf() and strchr(), but that modifies input which may be undesirable.
If the input is a stream rather than a string, then it is simpler:
int converted = 0 ;
int i = 0 ;
do
{
converted = fscanf( fd, "%d,", &output[i] ) ;
i++ ;
} while( !feof( fd ) && converted != 0 ) ;
I have not included any means to prevent output[i] from exceeding the bounds - you may need to consider that too.
Here is one way to do it:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
typedef struct
{
int* values;
int count;
}
output_t;
output_t Read(char input[])
{
int* values = NULL;
int count = 0;
char* pch = strtok(input,", ");
while (pch != NULL)
{
values = realloc(values,(count+1)*sizeof(*values));
values[count++] = atoi(pch);
pch = strtok(NULL,", ");
}
return (output_t){values,count};
}
And here is a usage example:
void Example()
{
char input[] = "1 , 2 , 34, 12, 46, 100";
output_t output = Read(input);
for (int i=0; i<output.count; i++)
printf("%d\n",output.values[i]);
free(output.values);
}
I'll throw my hat into the ring and do a single pass of the data. I estimate the required array size to be the worst case where every data is of the form "n," so two bytes per number, and resize it afterwards.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
typedef unsigned int uint32_t;
int main (void) {
char input[] = "1 , 2 , 34, 12, 46, 100";
uint32_t *output, *temp;
char *tok;
int elements = 0;
int len = 1 + strlen(input) / 2; // estimate max num of elements
output = malloc(len * sizeof(*output));
if (output == NULL)
exit(-1); // memory alloc error
tok = strtok(input, ", "); // parse the string
while (tok != NULL) {
if (elements >= len)
exit(-2); // error in length assumption
if (1 != sscanf(tok, "%u", output + elements))
exit(-3); // error in string format
elements++;
tok = strtok(NULL, ", ");
}
temp = realloc(output, elements * sizeof(*output)); // resize the array
if (temp == NULL)
exit(-4); // error in reallocating memory
output = temp;
for (len=0; len<elements; len++)
printf("%u ", output[len]);
printf("\n");
free(output);
return 0;
}
Program output:
1 2 34 12 46 100
Read through the string once to figure out how to size your array:
uint32_t n = 1;
for (uint32_t idx = 0; idx < strlen(input); idx++) {
if (input[idx] == ',') {
n++;
}
}
There's a different way to do this that doesn't require reading through the string, but it requires resizing the destination array as new elements come in, which makes the code more complex. It's easy enough to read through the string once for small strings.
Make your destination array:
uint32_t* output = NULL;
output = malloc(sizeof(*output) * n);
if (!output) {
fprintf(stderr, "Error: Could not allocate space for output array!\n");
exit(EXIT_FAILURE);
}
Populate your array. One way to do this without clobbering the string is to keep a couple pointers to the start and end of a substring that contains the desired numeric element in the comma-separated string, and just loop over all the characters in the string:
#define MAX_LEN 13
char* start = &input[0];
char* end = &input[0];
char entry[MAX_LEN];
uint32_t entry_idx = 0;
int finished = 0; // false
do {
end = strchr(start, ',');
if (!end) {
end = input + strlen(input);
finished = 1;
}
memcpy(entry, start, end - start);
entry[end - start] = '\0';
sscanf(entry, "%u", &output[entry_idx++]);
start = end + 1;
} while (!finished);
MAX_LEN is 13 because it is unlikely that a uint32_t will be longer than 13 digits. You can make this longer to future-proof this for computers made in the year 2100.
Be sure to free the array when you're done with it:
free(output);
output = NULL;
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <stdint.h>
int getsize(char* str, char* delimiters) //give the size of the final uint32_t array[]
{
int count = 0;
char* st = strdup(str), *t = strtok(st, delimiters);
while(t)
{
count++;
t = strtok(NULL, delimiters);
}
free(st);
return count;
}
uint32_t* Char_to_Array(char *data, char* delimiters, int *siz) //siz is a pointer to get the size of the array
{
char* st = strdup(data), *t = NULL; //dup string, strtok mage change on the passed string
*siz = getsize(data, delimiters);
uint32_t* buf=(uint32_t *)malloc((*siz)*4);
t = strtok(st, delimiters); //split string by " "
int i = 0;
while(t)
{
buf[i] = atoi(t);
t = strtok(NULL, delimiters);
i++;
}
free(st);
return buf;
}
here a test with a main function
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <stdint.h>
int main()
{
int getsize(char* str, char* delimiters), siz = 0, i = 0;
uint32_t* Char_to_Array(char *data, char* delimiters, int *x);
uint32_t* t = Char_to_Array("123, 156, 4658,7878", " ,", &siz);
while(i<siz)
{
printf("array[%d] = %d\n", i, t[i]);
i++;
}
free(t);
return 0;
}
2 pass approach:
1) Count the number of commas and allocate an array.
2) Parse the string - look for errors.
[Late to the uint32 comma party]
#include <errno.h>
#include <stdlib.h>
#include <stdbool.h>
#include <stdint.h>
#include <inttypes.h>
typedef struct {
uint32_t *u32;
size_t count;
bool error;
} CSV_32_T;
CSV_32_T CSV_to_int32_list(const char *csv) {
CSV_32_T list = { NULL, 1, false };
// 1st pass: Quickly go through list counting commas
const char *p = csv;
for (p = csv; *p; p++) {
if (*p == ',') {
list.count++;
}
}
size_t i = 0;
list.u32 = malloc(list.count * sizeof *list.u32);
if (list.u32) {
// 2nd pass: scan
p = csv;
for (i = 0; i < list.count; i++) {
if (i > 0 && *p++ != ',') {
break;
}
int n = 0;
if (1 != sscanf(p, "%" SCNu32 " %n", &list.u32[i], &n)) {
break;
}
p += n;
}
}
if (i != list.count || *p) {
free(list.u32);
return (CSV_32_T ) { NULL, 0, true } ;
}
return list;
}
void testCSV(const char *csv) {
CSV_32_T y = CSV_to_int32_list(csv);
printf("%d %zu \"%s\"\n", y.error, y.count, csv);
}
int main(void) {
testCSV("1 , 2 , 34, 12, 46, 100");
testCSV("1 2 , 34, 12, 46, 100");
return 0;
}
I am having trouble with a binary search on strings in c. I use the strcmp function to compare the strings, but I still get no output when I type in a name that I know is in the list.
#include <string.h>
#include <stdio.h>
#include <stdlib.h>
#define MAX_STRING_LEN 25
void insert_sata(char **strings, const char* filename, int size);
void allocate( char ***strings, int size);
int binary_search(char **strings, char *target, int start_idx, int end_idx);
int main(int argc, char* argv[]){
if(argc != 4){
printf("Wrong number of args");
}
char **pointer;
int size = atoi(argv[1]);
allocate(&pointer, size);
insert_data(pointer, argv[2], size);
int x;
int z = 1;
char search_name[MAX_STRING_LEN];
while( z == 1){
printf("\nEnter a name to search for: ");
scanf("%s", search_name);
x = binary_search(pointer, search_name, 0, size);
printf("\nContinue searching names? ( 1 = yes, 0 = No):");
scanf("%d", &z);
}
}
void allocate(char ***strings, int size){
int i;
*strings = malloc(sizeof(**strings) * size);
for( i = 0; i < size; i++)
{
(*strings)[i] = malloc(sizeof(char) * MAX_STRING_LEN);
}
}
void insert_data(char **strings, const char* filename, int size){
FILE *input;
input = fopen(filename, "r");
int i;
for (i = 0; i < size; i++){
fscanf(input,"%24s", strings[i]);
}
fclose(input);
}
int binary_search(char **strings, char *target, int start_idx, int end_idx){
int result;
int mid_idx = 0;
while( end_idx >= start_idx){
mid_idx = (end_idx + start_idx) / 2;
result = strcmp(strings[mid_idx], target);
if(result > 0){
end_idx = start_idx - 1;
}
else if (result < 0){
start_idx = mid_idx + 1;
}
else if( result == 0){
printf("%s was found in the set", target);
}
}
}
The binary search is the function that is giving me trouble. I do not recieve any seg faults or anything, just nothing is displayed when I search a name that is in the file. Here is the list of names that I scan into the program.
matt
susan
mark
david
aden
phil
erik
john
caden
mycah
Your input list isn't sorted and your program doesn't seem to try to sort it. Suppose you look for 'susan' - first comparision is 'susan' to 'aden', and the search area gets narrowed to last 5 items, while 'susan' is at the second position......
This:
if (result > 0) {
end_idx = start_idx - 1;
}
is probably mean to be:
if (result > 0) {
end_idx = mid_idx - 1;
}
The binary search algorithm requires that the list is sorted. Your example list isn't, so the algorithm will not work