Если Ваше все еще наличие проблемы, проверьте использование enctype в теге form
номер:
<form encoding="multipart/form-data" action="/upload">
Да:
<form enctype="multipart/form-data" action="/upload">
В отличие от других ответов, не требует C99.
Настоящая проблема здесь заключается в том, что не зная длину строки, которую вы будет нуждаться. Получить число так же просто, как sprintf ("% u", * num)
, используя num
для обхода вашего массива int
s, но сколько места тебе понадобится? Чтобы избежать переполнения буфера, вы должны отслеживать множество целых чисел.
size_t join_integers(const unsigned int *num, size_t num_len, char *buf, size_t buf_len) {
size_t i;
unsigned int written = 0;
for(i = 0; i < num_len; i++) {
written += snprintf(buf + written, buf_len - written, (i != 0 ? ", %u" : "%u"),
*(num + i));
if(written == buf_len)
break;
}
return written;
}
Обратите внимание, что я отслеживаю, какой объем буфера я использовал, и использую snprintf
, чтобы не переполнять конец. snprintf
будет прикреплять к \ 0
, но поскольку я использую buf + написанный
, я начну с \ 0
предыдущий snprintf
.
Используется:
int main() {
size_t foo;
char buf[512];
unsigned int numbers[] = { 10, 20, 30, 40, 1024 };
foo = join_integers(numbers, 5, buf, 512);
printf("returned %u\n", foo);
printf("numbers: %s\n", buf);
}
Выходы:
returned 20
numbers: 10, 20, 30, 40, 1024
Принудительное срабатывание ограничения вместо превышения:
char buf[15];
foo = join_integers(numbers, 5, buf, 14);
buf[14] = '\0';
Ожидаемые результаты:
returned 14
numbers: 10, 20, 30, 4
Фактически вы можете использовать такую библиотеку, как Glib , которая содержит такие функции, как
gchar * g_strjoin (const gchar * separator, ...);
Объединяет несколько строк в одну длинную строку с дополнительным разделителем, вставленным между каждой из них. Возвращенная строка должна быть освобождена с помощью g_free ().
(вам все равно нужно использовать g_snprintf ()
, возможно, с g_printf_string_upper_bound ()
, чтобы освободить место)
char buf [11 * sizeof (my_list)];
for (int n = 0, int j = 0; j < sizeof (my_list) / sizeof (my_list [0]); ++j)
n += sprintf (&buf [n], "%s%u", (j > 0) ? "," : "", my_list [j]);
unsigned *a; /* your input a[N] */
unsigned i,N;
char *b,*m;
b=m=malloc(1+N*11); /* for each of N numbers: 10 digits plus comma (plus end of string) */
for (i=0;i<N;++i)
b+=sprintf(b,"%u,",a[i]);
if (N>0) b[-1]=0; /* delete last trailing comma */
/* now use m */
free(m);
красиво, правда? :)
Что насчет этого?
char *join_int_list(const unsigned int *list, size_t n_items)
{
enum { SIZEOF_INT_AS_STR = sizeof("4294967295,")-1 };
char *space = malloc(SIZEOF_INT_AS_STR * n_items);
if (space != 0)
{
size_t i;
char *pad = "";
char *dst = space;
char *end = space + SIZEOF_INT_AS_STR * n_items;
for (i = 0; i < n_items; i++)
{
snprintf(dst, end - dst, "%s%u", pad, list[i]);
pad = ",";
dst += strlen(dst);
}
space = realloc(space, dst - space + 1);
}
return(space);
}
Вызывающий объект обязан освободить возвращаемый указатель и проверить, не является ли он нулевым перед его использованием. 'Realloc ()' освобождает дополнительное пространство, если выделенная сумма была слишком большой, чтобы окупить ее. Этот код беспечно предполагает, что значения действительно являются 32-битными целыми числами без знака; если они могут быть больше, то перечисление требует соответствующей настройки.
Протестированный код:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
char *join_int_list(const unsigned int *list, size_t n_items)
{
enum { SIZEOF_INT_AS_STR = sizeof("4294967295,")-1 };
char *space = malloc(SIZEOF_INT_AS_STR * n_items);
if (space != 0)
{
size_t i;
char *pad = "";
char *dst = space;
char *end = space + SIZEOF_INT_AS_STR * n_items;
for (i = 0; i < n_items; i++)
{
snprintf(dst, end - dst, "%s%u", pad, list[i]);
pad = ",";
dst += strlen(dst);
}
space = realloc(space, dst - space + 1);
}
return(space);
}
int main(void)
{
static unsigned int array[]= { 1, 2, 3, 49, 4294967295U, 0, 332233 };
char *str = join_int_list(array, sizeof(array)/sizeof(array[0]));
printf("join: %s\n", str);
free(str);
return(0);
}
Проверено с помощью valgrind - вроде нормально.
Обсуждение преобразования INT_MAX
или UINT_MAX
в строку:
Вы можете использовать sizeof ("," STRINGIZE (INT_MAX)) вместо жесткого кодирования. Макрос строкового преобразования - это обычный инструмент cpp, который можно определить как #define STRINGIZE_ (v) #v и #define STRINGIZE (v) STRINGIZE_ (v). - Р. Пейт
@R Pate: хорошая идея - да, вы могли бы сделать это довольно эффективно. На самом деле, здесь есть две интересные идеи: использование конкатенации строк с помощью sizeof () (скобки необходимы для ясности, но конкатенация строк происходит достаточно рано, чтобы компилятор не беспокоился) и использование операции преобразования строк в
INT_MAX
. - Джонатан ЛеффлерИспользование операции преобразования строки в
INT_MAX
не является хорошей идеей - это просто должно быть «постоянное выражение», а не обязательно последовательность цифр. Его можно определить как ((1 << 32) -1) или даже что-то странное, например __int_max, если компилятор позволяет вам использовать его везде, где вы можете использовать постоянное выражение. - caf
И @caf прав. Рассмотрим этот код:
#include <limits.h>
#include <stdio.h>
#undef INT_MAX
#define INT_MAX (INT_MIN-1 - 100 + 100)
#define QUOTER(x) #x
#define STRINGIZER(x) QUOTER(x)
enum { SIZEOF_INT_AS_STR = sizeof("4294967295,")-1 };
enum { SIZEOF_INT_AS_STR_1 = sizeof(STRINGIZER(INT_MAX) ",")-1 };
int main(void)
{
printf("size = %d = %d\n", SIZEOF_INT_AS_STR, SIZEOF_INT_AS_STR_1);
printf("INT_MAX = %d\n", INT_MAX);
printf("UINT_MAX = %u\n", UINT_MAX);
return(0);
}
Он даже не компилируется на MacOS X 10.5.8 с GCC 4.0. 1 - потому что идентификатор INT_MAX
не определен. Предварительная версия кода, которая не печатала INT_MAX
или UINT_MAX
, работала; он показал, что значение SIZEOF_INT_AS_STR_1
было 31 - значит, @caf был правильным. Добавление двойной проверки значений INT_MAX
и UINT_MAX
затем не удалось скомпилировать, что меня удивило. Взгляд на вывод gcc -E
показывает, почему:
enum { SIZEOF_INT_AS_STR = sizeof("4294967295,")-1 };
enum { SIZEOF_INT_AS_STR_1 = sizeof("((-INT_MAX - 1)-1 - 100 + 100)" ",")-1 };
int main(void)
{
printf("size = %d = %d\n", SIZEOF_INT_AS_STR, SIZEOF_INT_AS_STR_1);
printf("INT_MAX = %d\n", ((-INT_MAX - 1)-1 - 100 + 100));
printf("UINT_MAX = %u\n", (((-INT_MAX - 1)-1 - 100 + 100) * 2U + 1U));
return(0);
}
Как и предполагалось, строка для SIZEOF_IN_AS_STR_1
вовсе не является цифровой строкой. Препроцессор может вычислять выражение (сколько ему нужно), но не должен создавать строку цифр.
Расширение INT_MAX
оказывается в терминах INT_MIN
и INT_MIN
, в свою очередь,
f () объявлен с параметром char *
для целей прототипирования, просто измените char -> int
. Я интерпретировал вопрос как требующий вывода строки, а не просто кода для записи в файл.
#define PRINT(s, l, x, i) snprintf((s), (l), "%s%d", (i) ? ",":"", (x)[i]);
char *f(size_t len, char *x) {
size_t i, j = 0, k;
for(i = 0; i < len; ++i)
j += PRINT(NULL, 0, x, i);
char *result = malloc(k = ++j);
for(*result = i = j = 0; i < len; ++i)
j += PRINT(result + j, k - j, x, i);
return result;
}
Вот тестовая среда:
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
// put f() here
int main(int ac, char **av) {
for(int i = 1; i < ac; ++i) {
printf("%s\n", f(strlen(av[i]), av[i]));
}
return 0;
}
Вы, ребята, и ваши ненужные особые случаи, чтобы позаботиться о конечной запятой ... Дешевле просто уничтожить последнюю запятую, чтобы иметь условную проверку каждый раз, когда цикл запускается.
:)
#include <stdio.h>
char* toStr(int arr[], unsigned int arrSize, char buff[])
{
if (arr && arrSize && buff)
{
int* currInt = arr;
char* currStr = buff;
while (currInt < (arr + arrSize))
{
currStr += sprintf(currStr, "%d,", *currInt++);
}
*--currStr = '\0';
}
return buff;
}
int main()
{
int arr[] = {1234, 421, -125, 15251, 15251, 52};
char buff[1000];
printf("Arr is:%s\n", toStr(arr, 6, buff));
}
Предполагается, что buff достаточно велик, выделите его (длина наибольшего int + 2) * arrSize). Вдохновил мой memcpy :)
Edit Я понял, что раньше у меня был мозговой перд, и я мог просто увеличить на возвращаемое значение sprintf вместо сохранения temp. По-видимому, другие ответы также делают это, отредактировал мой ответ, чтобы удалить 2 ненужные строки.
Edit2 Похоже, непослушный победил меня! Его ответ практически идентичен моему и был отправлен ранее. Я смиренно предлагаю поставить ему +1.
Предположим, что когда вы упоминаете «для ведения журнала», вы имеете в виду запись в файл журнала, тогда ваше решение может выглядеть примерно так (псевдокодировано):
for (int x in array) {
fprintf(log, "%d", x);
if (! last element)
fputc(log, ',');
}
Если вы хотите поместить его в файл, ответ Стивена Шланскера подойдет.
Если вы хотите поместить его в строку, все усложняется. Вы можете использовать sprintf
, но вы должны быть осторожны, чтобы у вас не закончилось место в вашей строке. Если у вас есть совместимый с C99 snprintf
(Linux, BSD, не Windows), следующий (непроверенный, некомпилированный) код должен работать:
char *buf = malloc(1024); /* start with 1024 chars */
size_t len = 1024;
int pos = 0;
int rv;
int i;
for (i = 0; i < n; i++) {
rv = snprintf(buf+pos, len - pos, "%s%d", i = 0 ? "" : ",", my_list[i]);
if (rv < len - pos) {
/* it fit */
pos += rv;
} else {
len *= 2;
buf = realloc(buf, len);
if (!buf) abort();
i--; /* decrement i to repeat the last iteration of the loop */
}
}
return buf;
Вызывающий должен затем освободить buf
.
Лично для простоты и, вероятно, скорости, я бы выделил большой буфер , с пространством для массива размером «4 294 967 295» и «,» для каждого элемента. Однако при создании списка это неэффективно по пространству!
Затем я бы вставил туда целые числа и добавил "," ко всем элементам
Наконец, я перераспределил указатель, чтобы у него было не больше места, чем обязательный. (size = strlen)
sprintf: В случае успеха возвращается общее количество записанных символов. Это количество не включает дополнительный нулевой символ, автоматически добавляемый в конец строки.
Таким образом вы отслеживаете, где strcpy находится в строке. :)
Надеюсь, это поможет! : )
И если вы хотите просто распечатать их, посмотрите вместо них другие ответы. (цикл for и printf)
К сожалению, всегда будет три случая:
Метод join
скрывает эту сложность для вас, поэтому он такой красивый.
В C я бы сделал:
for (i = 0; i < len; i++)
{
if (i > 0) /* You do need this separate check, unfortunately. */
output(",");
output(item[i]);
}
Где output
, однако, вы добавляете к строке. Это может быть просто strcat
в предварительно выделенном буфере или printf
для некоторого потока (например, поток памяти, о котором я узнал сегодня в Создание потока FILE * что приводит к строке : -).
Если вас раздражает выполнение этой проверки каждый раз для всех i> = 1, вы можете сделать:
if (i > 0)
{
output(item[0]);
for (i = 1; i < len; i++)
{
output(",");
output(item[i]);
}
}
#include <stdio.h>
#include <stdlib.h>
/* My approach is to count the length of the string required. And do a single alloc.
Sure you can allocate more, but I don't know for how long this data will be retained.
*/
#define LEN(a) (sizeof a / sizeof *a)
int main(void) {
unsigned a[] = {1, 23, 45, 523, 544};
int i, str_len=0, t_written=0;
char tmp[11]; /* enough to fit the biggest unsigned int */
for(i = 0; i < LEN(a); i++)
str_len += sprintf(tmp, "%d", a[i]);
/* total: we need LEN(a) - 1 more for the ',' and + 1 for '\0' */
str_len += LEN(a);
char *str = malloc(str_len);
if (!str)
return 0;
if (LEN(a) > 1) {
t_written += sprintf(str+t_written, "%d", a[0]);
for(i = 1; i < LEN(a); i++)
t_written += sprintf(str+t_written, ",%d", a[i]);
} else if (LEN(a) == 1)
t_written += sprintf(str+t_written, "%d", a[0]);
printf("%s\n", str);
free(str);
return 0;
}
void join(int arr[], int len, char* sep, char* result){
if(len==0){
*result='\0';
} else {
itoa(arr[0],result,10);
if(len > 1){
strcat(result,sep);
join(arr+1,len-1,sep,result+strlen(result));
}
}
}